{"openapi":"3.1.0","info":{"title":"ScormStack API","version":"1.0.0","description":"The ScormStack API allows you to programmatically create, manage, and export learning courses.\n\n## Authentication\n\nAll API endpoints require authentication using a Personal Access Token (PAT):\n\n```bash\ncurl -H \"Authorization: Bearer pat_xxxxxxxxxxxxxxxxxxxxx\" \\\n  https://app.scormstack.com/api/v1/courses\n```\n\n### Getting a Token\n\n1. Log into the ScormStack web application\n2. Navigate to **Settings → Workspace → API Tokens**\n3. Click **Create Token** and select the required scopes\n4. Copy the token immediately (it won't be shown again)\n\nPersonal tokens require an active personal Trial, Pro or Enterprise plan. They access only your own personal courses and their media or personal-library media, never workspace resources. Workspace tokens require an eligible plan in their selected workspace. The plan is checked on every request, including Trial expiry. Tokens remain bound to their original space.\n\n### Token Scopes\n\nTokens can be created with specific scopes to limit access:\n\n| Scope | Description |\n|-------|-------------|\n| `api:*` | Full access to all API endpoints |\n| `courses:read` | Read course information and list accessible themes |\n| `courses:create` | Create new courses |\n| `courses:update` | Edit and publish courses, including starting package exports |\n| `courses:delete` | Delete courses |\n| `sections:*` | Full access to sections |\n| `slides:*` | Full access to slides |\n| `blocks:*` | Full access to blocks |\n| `assets:read` | List and view assets |\n| `assets:create` | Upload new assets |\n| `assets:delete` | Delete assets |\n| `locales:read` | List locales and export translations |\n| `locales:write` | Import translations |\n| `analytics:read` | List and export course learner analytics |\n| `analytics:delete` | Delete course learner analytics |\n\n## Rate Limiting\n\nAPI requests are limited to **100 requests per minute** per token. Rate limit headers are included in all responses:\n\n- `X-RateLimit-Limit`: Maximum requests per window\n- `X-RateLimit-Remaining`: Requests remaining in current window\n- `X-RateLimit-Reset`: Unix timestamp when the window resets\n\n## Errors\n\nThe API uses standard HTTP status codes and returns error details in JSON format:\n\n```json\n{\n  \"error\": \"Validation failed\",\n  \"code\": \"VALIDATION_ERROR\",\n  \"details\": {\n    \"field\": \"title\",\n    \"reason\": \"Title is required\"\n  }\n}\n```\n\n## Block Types and Content Schemas\n\nEach block type has a specific content structure. Use the appropriate schema based on the `type` field:\n\n| Block Type | Content Schema | Description |\n|------------|----------------|-------------|\n| `text` | TextBlockContent | Text content with heading and paragraphs |\n| `image` | ImageBlockContent | Image with caption and positioning options |\n| `video` | VideoBlockContent | YouTube, Vimeo, or uploaded video |\n| `audio` | AudioBlockContent | Audio player with visualization |\n| `flow` | FlowBlockContent | Step-by-step guided experience |\n| `timeline` | TimelineBlockContent | Chronological events with expandable details |\n| `flashcards` | FlashcardsBlockContent | Interactive flashcard deck |\n| `accordion` | AccordionBlockContent | Collapsible content sections |\n| `tabs` | TabsBlockContent | Tabbed content panels |\n| `assessment` | AssessmentBlockContent | Multi-question quiz assessment |\n| `fill_in_blank` | FillInBlankBlockContent | Fill-in-the-blank assessment |\n| `matching` | MatchingBlockContent | Match items between columns |\n| `click_on_image` | ClickOnImageBlockContent | Click on correct image areas |\n| `interactive_image` | InteractiveImageBlockContent | Image with clickable hotspots |\n| `web_simulation` | WebSimulationBlockContent | Interactive app walkthrough |\n| `success_meter` | SuccessMeterBlockContent | Scenario-based assessment |\n| `categorization` | CategorizationBlockContent | Sort items into categories |\n| `sorting` | SortingBlockContent | Sort items into a sequence |\n| `open_response` | OpenResponseBlockContent | Free-text response |\n| `callout` | CalloutBlockContent | Highlighted info/tip/warning box |\n| `list` | ListBlockContent | Bullet, numbered, or icon list |\n| `separator` | SeparatorBlockContent | Visual divider between sections |\n| `resources` | ResourcesBlockContent | Downloadable resources list |\n| `embed` | EmbedBlockContent | Embedded iframe content |\n| `pdf` | PdfBlockContent | PDF viewer |\n| `slide_intro` | SlideIntroBlockContent | Lesson introduction slide |\n| `navigation_button` | NavigationButtonBlockContent | Navigation control button |\n| `reactions` | ReactionsBlockContent | Single-choice learner reaction feedback |\n\nSee the **Schemas** section below for detailed content structure of each block type.\n","contact":{"name":"ScormStack Support","url":"https://scormstack.com/support"}},"servers":[{"url":"/api/v1","description":"V1 API"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"PAT","description":"Personal Access Token (format: pat_xxx...)"}},"schemas":{"Theme":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"properties":{"type":"object","additionalProperties":true,"description":"Reusable theme configuration, including colors and fonts."},"is_system":{"type":"boolean","nullable":true},"is_default":{"type":"boolean","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}}},"Error":{"type":"object","description":"Represents an API error response.","properties":{"error":{"type":"string","description":"A human-readable error message describing what went wrong.","example":"Course not found"},"code":{"type":"string","description":"A machine-readable error code for programmatic handling.","example":"RESOURCE_NOT_FOUND"},"details":{"type":"object","description":"Additional context about the error, such as validation failures.","example":{"field":"title","reason":"Title is required"}}},"required":["error"],"example":{"error":"Validation failed","code":"VALIDATION_ERROR","details":{"field":"title","reason":"Title must be between 1 and 255 characters"}}},"Pagination":{"type":"object","description":"Pagination metadata for list responses.","properties":{"page":{"type":"integer","description":"Current page number (1-indexed).","example":1},"limit":{"type":"integer","description":"Number of items per page.","example":20},"total":{"type":"integer","description":"Total number of items across all pages.","example":42},"totalPages":{"type":"integer","description":"Total number of pages available.","example":3}},"example":{"page":1,"limit":20,"total":42,"totalPages":3}},"LearnerAnalytics":{"type":"object","description":"A learner's current course analytics and aggregated session data.","properties":{"id":{"type":"string","format":"uuid"},"learner_id":{"type":"string","example":"learner-1042"},"learner_email":{"type":["string","null"],"format":"email","example":"ada@example.com"},"learner_name":{"type":["string","null"],"example":"Ada Lovelace"},"learner_pseudo":{"type":["string","null"],"example":"ada-l"},"score":{"type":["number","null"],"example":92},"progress":{"type":"number","example":100},"completion_status":{"type":["string","null"],"example":"completed"},"success_status":{"type":"string","example":"passed"},"lesson_status":{"type":["string","null"],"example":"passed"},"session_count":{"type":"integer","example":3},"session_time_seconds":{"type":"integer","example":2840},"last_slide_id":{"type":["string","null"],"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"suspend_data":{"description":"Raw learner suspend data. Present only when includeFullData=true."}},"required":["id","learner_id","learner_email","learner_name","learner_pseudo","score","progress","completion_status","success_status","lesson_status","session_count","session_time_seconds","last_slide_id","created_at","updated_at"]},"LearnerAnalyticsSummary":{"type":"object","properties":{"totalLearners":{"type":"integer","example":42},"completedCount":{"type":"integer","example":31},"successCount":{"type":"integer","example":27},"averageTimeSpentSeconds":{"type":"integer","example":2135}},"required":["totalLearners","completedCount","successCount","averageTimeSpentSeconds"]},"LearnerAnalyticsDeleteRequest":{"type":"object","additionalProperties":false,"properties":{"learner_ids":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"string"},"example":["learner-1042","learner-1043"]}},"required":["learner_ids"]},"WebhookCoursePublished":{"type":"object","description":"Payload delivered when a course export has completed.","properties":{"course_id":{"type":"string","format":"uuid","description":"ID of the exported course.","example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"title":{"type":"string","description":"Course title at export time.","example":"Introduction to JavaScript"},"lms_course_id":{"type":"string","nullable":true,"description":"Optional LMS course identifier configured in course settings.","example":"LMS-COURSE-1024"},"download_url":{"type":"string","format":"uri","description":"Signed URL to download the export package.","example":"https://exports.scormstack.com/exports/req_123/course_scorm2004_with_assets.zip?X-Amz-Signature=..."},"expiration_date":{"type":"string","format":"date-time","description":"UTC timestamp when the download URL expires.","example":"2024-01-22T14:45:00.000Z"},"export_type":{"type":"string","description":"Export format.","enum":["scorm","xapi","cmi5","html"],"example":"scorm"},"request_id":{"type":"string","nullable":true,"description":"Internal export request identifier.","example":"req_1234567890abcdef"}},"required":["course_id","title","download_url","expiration_date","export_type"]},"CoursePublishRequest":{"type":"object","description":"Options used to publish or export a course. Dynamic refresh accepts only refresh_dynamic_content_only, target_export_id, and optional notify_webhooks; existing export settings are reused.","properties":{"refresh_dynamic_content_only":{"type":"boolean","default":false,"description":"Refresh an existing completed dynamic package in place, without generating a ZIP or consuming a new export slot. Requires target_export_id. Omit creation options (format, version, locale, etc.); saved export settings are preserved. Requires dynamic updates on the current plan."},"target_export_id":{"type":"string","format":"uuid","description":"export_id of the existing completed dynamic package for this course, returned by creation or GET /courses/{courseId}/exports. Required only with refresh_dynamic_content_only: true."},"dynamic_content":{"type":"boolean","default":false,"description":"Create a package that loads hosted course data and can later be refreshed without replacing the LMS ZIP. Requires dynamic updates on the current plan."},"notify_webhooks":{"type":"boolean","default":true,"description":"Send configured workspace webhooks: course_published for package creation, dynamic_course_updated for a dynamic refresh. Set false to suppress delivery."},"format":{"type":"string","enum":["scorm","xapi","cmi5","html","public_link"],"default":"scorm","description":"`cmi5` creates a cmi5 course package. `html` creates a downloadable HTML package. `public_link` publishes a hosted learner URL."},"version":{"type":"string","enum":["1.2","2004"],"description":"SCORM version. Ignored for xAPI, cmi5, HTML package, and public links."},"include_assets":{"type":"boolean","description":"Bundle media assets into the SCORM/xAPI/cmi5 package. This makes the export asynchronous.","default":false},"locale":{"type":"string","nullable":true,"description":"Locale code to export, `all` for multi-locale packages, or null for the course default.","example":"fr"},"slide_selection":{"type":"string","enum":["all","select"],"default":"all"},"slide_range":{"type":"string","description":"Slide range when `slide_selection` is `select`, e.g. `1,3,5-8`.","example":"1-5,8"},"track_progress":{"type":"boolean","description":"Enable ScormStack learner progress tracking where supported."},"learner_identification_type":{"type":"string","enum":["none","email","pseudo","name"],"default":"none"},"publish_mode":{"type":"string","enum":["default","new","update"],"description":"Public link mode. `update` requires `target_embed_id`."},"target_embed_id":{"type":"string","nullable":true,"description":"Existing public link embed ID to update."},"share_option":{"type":"string","enum":["link","embed","email","linkedin"],"default":"link","description":"Preferred sharing mode, recorded as metadata. Neither email nor linkedin sends a message or posts anything; those actions require a separate user action in the app."},"password_protection":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"mode":{"type":"string","enum":["auto","manual"],"default":"auto"},"password":{"type":"string","nullable":true,"description":"A non-blank password is required when protection is enabled and mode is `manual`."}},"allOf":[{"if":{"properties":{"enabled":{"const":true},"mode":{"const":"manual"}},"required":["enabled","mode"]},"then":{"required":["password"],"properties":{"password":{"type":"string","minLength":1,"pattern":"\\S"}}}}]}},"example":{"format":"scorm","version":"2004","include_assets":true,"locale":"fr","slide_selection":"select","slide_range":"1-8","track_progress":true,"learner_identification_type":"email"}},"CourseExportSettings":{"type":"object","description":"Saved export settings. Null means the value was not recorded. Passwords, worker payloads, and private storage keys are excluded.","properties":{"version":{"type":"string","nullable":true},"locale":{"type":"string","nullable":true},"resolved_locale":{"type":"string","nullable":true},"slide_selection":{"type":"string","nullable":true},"slide_range":{"type":"string","nullable":true},"include_assets":{"type":"boolean","nullable":true},"enable_debugging":{"type":"boolean","nullable":true},"track_progress":{"type":"boolean","nullable":true},"learner_identification_type":{"type":"string","nullable":true},"dynamic_content":{"type":"boolean"},"publish_mode":{"type":"string","nullable":true},"share_option":{"type":"string","nullable":true},"password_protected":{"type":"boolean","nullable":true}}},"CourseExport":{"type":"object","properties":{"export_id":{"type":"string","format":"uuid","description":"Pass this ID as target_export_id to update a dynamic package."},"request_id":{"type":"string","format":"uuid","description":"Legacy alias for export_id."},"course_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["completed"]},"format":{"type":"string","description":"Normalized export format, such as scorm, xapi, cmi5, html, or public_link."},"export_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true},"completed_at":{"type":"string","format":"date-time","nullable":true},"dynamic_content":{"type":"boolean"},"dynamic_course_data_updated_at":{"type":"string","format":"date-time","nullable":true},"settings":{"$ref":"#/components/schemas/CourseExportSettings"},"filename":{"type":"string","nullable":true},"url":{"type":"string","format":"uri","nullable":true},"embed_id":{"type":"string","nullable":true},"status_url":{"type":"string"}}},"CourseExportList":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CourseExport"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"CoursePublishResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"export_id":{"type":"string","format":"uuid","description":"Export ID; use as target_export_id for dynamic refresh. Same value as request_id."},"request_id":{"type":"string","example":"req_1234567890abcdef"},"status":{"type":"string","enum":["pending","processing","completed","failed"],"example":"completed"},"format":{"type":"string","enum":["scorm","xapi","cmi5","html","public_link"]},"dynamic_content":{"type":"boolean"},"refresh_dynamic_content_only":{"type":"boolean","description":"True when this response confirms refreshing an existing dynamic package without generating a new ZIP."},"dynamic_course_data_url":{"type":"string","format":"uri","nullable":true},"dynamic_course_data_script_url":{"type":"string","format":"uri","nullable":true},"dynamic_course_data_updated_at":{"type":"string","format":"date-time","nullable":true},"download_url":{"type":"string","format":"uri","description":"Signed package URL for completed package exports."},"url":{"type":"string","format":"uri","description":"Hosted learner URL for public link publishes."},"status_url":{"type":"string","description":"Polling URL returned for asynchronous package exports."},"expires_at":{"type":"string","format":"date-time"},"embed_id":{"type":"string"}}}}},"CoursePublishStatus":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"export_id":{"type":"string","format":"uuid","description":"Export ID; use as target_export_id for dynamic refresh. Same value as request_id."},"request_id":{"type":"string"},"course_id":{"type":"string","format":"uuid"},"settings":{"$ref":"#/components/schemas/CourseExportSettings"},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true},"completed_at":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string","enum":["pending","processing","completed","failed"]},"format":{"type":"string","enum":["scorm","xapi","cmi5","html","public_link"]},"progress":{"type":"number"},"current_step":{"type":"string"},"dynamic_content":{"type":"boolean"},"dynamic_course_data_url":{"type":"string","format":"uri","nullable":true},"dynamic_course_data_script_url":{"type":"string","format":"uri","nullable":true},"dynamic_course_data_updated_at":{"type":"string","format":"date-time","nullable":true},"download_url":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"error":{"type":"string"}}}}},"WebhookEvent":{"type":"object","description":"Standard webhook event envelope (Stripe-style).","properties":{"id":{"type":"string","description":"Unique event identifier.","example":"evt_1a2b3c4d5e6f7g8h9i0j"},"object":{"type":"string","description":"Object type.","example":"event"},"type":{"type":"string","description":"Event type.","example":"course_published"},"created":{"type":"integer","description":"Unix timestamp when the event was created.","example":1705327800},"livemode":{"type":"boolean","description":"Whether this event was generated in live mode.","example":false},"data":{"type":"object","properties":{"object":{"$ref":"#/components/schemas/WebhookCoursePublished"}},"required":["object"]}},"required":["id","object","type","created","livemode","data"],"example":{"id":"evt_1a2b3c4d5e6f7g8h9i0j","object":"event","type":"course_published","created":1705327800,"livemode":false,"data":{"object":{"course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Introduction to JavaScript","lms_course_id":"LMS-COURSE-1024","download_url":"https://exports.scormstack.com/exports/req_123/course_scorm2004_with_assets.zip?X-Amz-Signature=...","expiration_date":"2024-01-22T14:45:00.000Z","export_type":"scorm","request_id":"req_1234567890abcdef"}}}},"Course":{"type":"object","description":"Represents a learning course in ScormStack.\n\nA course is the top-level container for learning content. It contains sections (optional organizational units) and slides (the actual content pages).","properties":{"theme_id":{"type":"string","format":"uuid","nullable":true,"description":"Existing theme ID from GET /themes. Must be a system theme, owned by the token user, or shared through a course the user can access in the token workspace. null clears the theme selection; omission preserves it on update.","example":"a1b2c3d4-e5f6-4789-abcd-ef1234567890"},"theme_config":{"type":"object","nullable":true,"additionalProperties":true,"description":"Course-specific theme overrides (for example colors, fonts, borderRadius or customCss); does not modify the shared theme. On update, replaces the entire override object, rather than merging it. null clears overrides; omission preserves them. Changing theme_id alone retains existing overrides.","example":{"colors":{"primary":"#1d4ed8"},"fonts":{"heading":"Arial","body":"Arial"}}},"id":{"type":"string","format":"uuid","description":"Unique identifier for the course.","example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"title":{"type":"string","description":"The display title of the course shown to learners.","example":"Introduction to JavaScript"},"description":{"type":"string","nullable":true,"description":"A brief description of the course content and objectives.","example":"Learn the fundamentals of JavaScript programming, from variables to functions."},"cover_image":{"type":"string","nullable":true,"description":"URL to the course cover image displayed in course listings.","example":"https://assets.scormstack.com/courses/js-intro/cover.jpg"},"user_id":{"type":"string","format":"uuid","description":"ID of the user who owns this course.","example":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234"},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the course was created.","example":"2024-01-15T10:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","description":"Timestamp when the course was last modified.","example":"2024-01-20T14:45:00.000Z"},"settings":{"type":"object","nullable":true,"description":"Course-level settings and configuration.","properties":{"grading_policy":{"type":"object","description":"Advanced grading policy. Omit unless configuring weighted grading; an enabled policy must include GRADER and GRADE_CUTOFFS.","additionalProperties":true,"properties":{"enabled":{"type":"boolean","description":"Whether grading is enabled for this course.","example":false}}},"navigation":{"type":"object","description":"Navigation behavior settings.","properties":{"allow_skip":{"type":"boolean","description":"Whether learners can skip ahead in the course.","example":false}}}},"example":{"navigation":{"allow_skip":false}}}},"example":{"id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Introduction to JavaScript","description":"Learn the fundamentals of JavaScript programming, from variables to functions.","cover_image":"https://assets.scormstack.com/courses/js-intro/cover.jpg","user_id":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234","created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z","settings":null}},"CourseCreate":{"type":"object","description":"Request body for creating a new course.","properties":{"theme_id":{"type":"string","format":"uuid","nullable":true,"description":"Existing theme ID from GET /themes. Must be a system theme, owned by the token user, or shared through a course the user can access in the token workspace. null clears the theme selection; omission preserves it on update.","example":"a1b2c3d4-e5f6-4789-abcd-ef1234567890"},"theme_config":{"type":"object","nullable":true,"additionalProperties":true,"description":"Course-specific theme overrides (for example colors, fonts, borderRadius or customCss); does not modify the shared theme. On update, replaces the entire override object, rather than merging it. null clears overrides; omission preserves them. Changing theme_id alone retains existing overrides.","example":{"colors":{"primary":"#1d4ed8"},"fonts":{"heading":"Arial","body":"Arial"}}},"owner_email":{"type":"string","format":"email","maxLength":254,"description":"Optional owner email. Must match one existing member of the token workspace (or its owner), ignoring case and surrounding whitespace. Does not invite or create a user. Use either owner_email or owner_id, not both. If neither is provided, the token user owns the course. The response exposes the owner as user_id.","example":"jordan@example.com"},"owner_id":{"type":"string","format":"uuid","description":"Optional UUID alternative to owner_email. Must identify an existing member of the token workspace (or its owner). Use one selector only. If neither is provided, the token user owns the course. The assigned owner is returned as user_id. Does not change the course workspace.","example":"e5f6a7b8-c9d0-4234-af12-345678901234"},"title":{"type":"string","minLength":1,"maxLength":255,"description":"The display title for the course. Required.","example":"Introduction to JavaScript"},"description":{"type":"string","description":"Optional description of the course.","example":"Learn the fundamentals of JavaScript programming."},"cover_image":{"type":"string","format":"uri","description":"URL to the course cover image.","example":"https://example.com/cover.jpg"},"settings":{"type":"object","description":"Optional course settings.","additionalProperties":true,"properties":{"grading_policy":{"type":"object","additionalProperties":true,"description":"Advanced grading policy. Omit unless configuring weighted grading; an enabled policy must include GRADER and GRADE_CUTOFFS.","properties":{"enabled":{"type":"boolean","example":false}}},"navigation":{"type":"object","description":"Navigation behavior settings.","properties":{"allow_skip":{"type":"boolean","description":"Whether learners can skip ahead in the course.","example":false}}}}},"default_locale":{"oneOf":[{"type":"string","description":"Language code for the course source/default locale.","example":"fr"},{"type":"object","description":"Detailed default locale configuration. `language_code` is required; missing names and direction are inferred from the locale dictionary when possible.","properties":{"language_code":{"type":"string","description":"Language code, e.g. `fr`, `en`, `pt-BR`.","example":"fr"},"language_name":{"type":"string","description":"English display name. Inferred if omitted.","example":"French"},"native_name":{"type":"string","description":"Native display name. Inferred if omitted.","example":"Français"},"text_direction":{"type":"string","enum":["ltr","rtl"],"description":"Text direction. Inferred if omitted.","example":"ltr"},"system_labels":{"type":"object","description":"Optional system label overrides. If omitted, built-in labels for supported languages are used.","additionalProperties":true,"example":{"flow.start_again":"Recommencer"}}},"required":["language_code"],"additionalProperties":true}],"nullable":true,"description":"Creates or updates the matching `course_locales` row and marks it as the course default (`is_default=true`). Use this when the course source content is not English."}},"required":["title"],"example":{"title":"Introduction to JavaScript","description":"Learn the fundamentals of JavaScript programming.","default_locale":"fr"}},"CourseUpdate":{"type":"object","description":"Request body for updating course metadata. To set the course source/default language during creation, use `default_locale` on `POST /courses` or `POST /courses/import`.","properties":{"theme_id":{"type":"string","format":"uuid","nullable":true,"description":"Existing theme ID from GET /themes. Must be a system theme, owned by the token user, or shared through a course the user can access in the token workspace. null clears the theme selection; omission preserves it on update.","example":"a1b2c3d4-e5f6-4789-abcd-ef1234567890"},"theme_config":{"type":"object","nullable":true,"additionalProperties":true,"description":"Course-specific theme overrides (for example colors, fonts, borderRadius or customCss); does not modify the shared theme. On update, replaces the entire override object, rather than merging it. null clears overrides; omission preserves them. Changing theme_id alone retains existing overrides.","example":{"colors":{"primary":"#1d4ed8"},"fonts":{"heading":"Arial","body":"Arial"}}},"owner_email":{"type":"string","format":"email","maxLength":254,"description":"Assign ownership by an existing workspace member's email (case-insensitive; surrounding whitespace ignored). Use either owner_email or owner_id, not both. Omit both to keep the current owner. The new owner becomes course admin and the former owner remains an editor; ownership, roles and supplied metadata update atomically. No invitation is sent. The response exposes the owner as user_id.","example":"jordan@example.com"},"owner_id":{"type":"string","format":"uuid","description":"UUID alternative to owner_email for assigning an existing workspace member. Use one selector only; omit both to keep the current owner. The new owner becomes course admin; the previous owner remains an editor. Reassigning the same owner is supported. Ownership, roles and supplied metadata update atomically. The response exposes the owner as user_id.","example":"e5f6a7b8-c9d0-4234-af12-345678901234"},"title":{"type":"string","minLength":1,"maxLength":255,"description":"The display title for the course.","example":"Introduction to JavaScript"},"description":{"type":"string","description":"Optional description of the course.","example":"Learn the fundamentals of JavaScript programming."},"cover_image":{"type":"string","format":"uri","nullable":true,"description":"URL to the course cover image.","example":"https://example.com/cover.jpg"},"settings":{"type":"object","description":"Optional course settings.","additionalProperties":true}},"example":{"title":"Updated JavaScript Course","description":"Updated course description."}},"Section":{"type":"object","description":"Represents a section within a course.\n\nSections are optional organizational units that group related slides together. They appear in the course navigation and help learners understand the course structure.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for the section.","example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"},"course_id":{"type":"string","format":"uuid","description":"ID of the course this section belongs to.","example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"title":{"type":"string","description":"Display title of the section.","example":"Getting Started"},"description":{"type":"string","nullable":true,"description":"Brief description of what this section covers.","example":"Set up your development environment and write your first code."},"icon":{"type":"string","nullable":true,"description":"Icon name from the icon library (e.g., 'rocket', 'book', 'code').","example":"rocket"},"cover_image":{"type":"string","nullable":true,"description":"URL to an optional section cover image.","example":"https://assets.scormstack.com/sections/getting-started.jpg"},"order_index":{"type":"integer","description":"Position of this section in the course (0-indexed).","example":0},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the section was created.","example":"2024-01-15T10:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","description":"Timestamp when the section was last modified.","example":"2024-01-20T14:45:00.000Z"}},"example":{"id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Getting Started","description":"Set up your development environment and write your first code.","icon":"rocket","cover_image":null,"order_index":0,"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"}},"SectionCreate":{"type":"object","description":"Request body for creating a new section.","properties":{"title":{"type":"string","minLength":1,"maxLength":255,"description":"Display title for the section. Required.","example":"Getting Started"},"description":{"type":"string","description":"Optional description of the section.","example":"Set up your development environment."},"icon":{"type":"string","description":"Optional icon name.","example":"rocket"},"cover_image":{"type":"string","format":"uri","description":"Optional cover image URL."},"order_index":{"type":"integer","description":"Position in the course. If omitted, appends to end.","example":0}},"required":["title"],"example":{"title":"Getting Started","description":"Set up your development environment.","icon":"rocket"}},"SlideProperties":{"type":"object","description":"Slide properties stored under content. On update, only supplied flags are merged into existing content; omitted flags and other settings are preserved. Saved values are retained but ignored while the slide has variant assignments, and apply again when all assignments are removed.","properties":{"optional":{"type":"boolean","description":"Exclude this slide from course and section progress and completion requirements. Defaults to false when absent. Ignored while the slide has variant assignments; variant rules apply instead."},"show_in_toc":{"type":"boolean","description":"Show on homepage: include this slide in the homepage table of contents. Defaults to true when absent. Ignored while the slide has variant assignments; variant rules apply instead."},"hide_in_navigation":{"type":"boolean","description":"Hide this slide from sidebar navigation and skip it with Next/Previous. Explicit Go to Slide buttons or Embed calls targeting its ID can still open it. Defaults to false when absent. Independent of homepage visibility and optional status. Ignored while the slide has variant assignments; variant rules apply instead."}},"additionalProperties":false},"SlideContent":{"type":["object","null"],"description":"Stored slide content/settings, including optional, show_in_toc, hide_in_navigation and layoutGroups. Missing flags retain legacy behavior: required, shown on the homepage and included in navigation. These three flags are ignored while variants are assigned; variant rules control visibility and completion.","properties":{"optional":{"type":"boolean","description":"Exclude this slide from course and section progress and completion requirements. Defaults to false when absent. Ignored while the slide has variant assignments; variant rules apply instead."},"show_in_toc":{"type":"boolean","description":"Show on homepage: include this slide in the homepage table of contents. Defaults to true when absent. Ignored while the slide has variant assignments; variant rules apply instead."},"hide_in_navigation":{"type":"boolean","description":"Hide this slide from sidebar navigation and skip it with Next/Previous. Explicit Go to Slide buttons or Embed calls targeting its ID can still open it. Defaults to false when absent. Independent of homepage visibility and optional status. Ignored while the slide has variant assignments; variant rules apply instead."}},"additionalProperties":true},"Slide":{"type":"object","description":"Represents a slide (content page) within a course.\n\nSlides are the main content containers. Each slide contains one or more blocks that make up the actual learning content.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for the slide.","example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"},"course_id":{"type":"string","format":"uuid","description":"ID of the course this slide belongs to.","example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"section_id":{"type":"string","format":"uuid","nullable":true,"description":"ID of the section this slide belongs to (null if not in a section).","example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"},"title":{"type":"string","description":"Display title of the slide shown in navigation.","example":"Variables and Data Types"},"content":{"$ref":"#/components/schemas/SlideContent"},"order_index":{"type":"integer","description":"Position of this slide within its section or course (0-indexed).","example":0},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the slide was created.","example":"2024-01-15T10:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","description":"Timestamp when the slide was last modified.","example":"2024-01-20T14:45:00.000Z"}},"example":{"id":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","section_id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","title":"Variables and Data Types","order_index":0,"content":{"optional":false,"show_in_toc":true,"hide_in_navigation":false},"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"}},"SlideCreate":{"type":"object","description":"Request body for creating a new slide. Set optional, show_in_toc and hide_in_navigation inside content. If omitted, the slide is required, shown on the homepage and included in navigation.","properties":{"content":{"$ref":"#/components/schemas/SlideProperties"},"title":{"type":"string","minLength":1,"maxLength":255,"description":"Display title for the slide. Required.","example":"Variables and Data Types"},"section_id":{"type":"string","format":"uuid","description":"Optional section ID to place the slide in.","example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"},"order_index":{"type":"integer","description":"Position in the section/course. If omitted, appends to end.","example":0}},"required":["title"],"example":{"title":"Variables and Data Types","section_id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"}},"SlideUpdate":{"type":"object","description":"Slide fields to update. Omitted fields are kept unchanged. Supplied content flags are merged into existing content, preserving other flags and settings such as layoutGroups. An empty content object leaves content unchanged. Use explicit booleans to change flags; null is not accepted.","properties":{"content":{"$ref":"#/components/schemas/SlideProperties"},"title":{"type":"string","minLength":1,"maxLength":255},"section_id":{"type":["string","null"],"format":"uuid","description":"Section in this course, or null to remove the slide from its section."},"order_index":{"type":"integer","minimum":0}},"additionalProperties":false},"Block":{"type":"object","description":"Represents a content block on a slide.\n\nBlocks are the building blocks of course content. Each block has a type (text, image, video, quiz, etc.) and type-specific content.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for the block.","example":"blk_d4e5f6a7-b8c9-0123-def1-234567890123"},"type":{"type":"string","description":"The block type determines what content structure is expected.","example":"text","enum":["slide_intro","separator","text","image","audio","video","embed","pdf","callout","list","table","accordion","tabs","flashcards","timeline","flow","interactive_image","web_simulation","scene","resources","assessment","fill_in_blank","matching","click_on_image","drag_and_drop","success_meter","categorization","sorting","open_response","navigation_button","reactions","time_requirements"]},"variant":{"type":"string","description":"Block variant for types that have multiple layouts (e.g., 'heading' vs 'paragraph' for text).","example":"heading"},"title":{"type":"string","nullable":true,"description":"Optional title for the block (used in some block types).","example":"Introduction"},"content":{"type":"object","nullable":true,"description":"Block content - structure varies by block type. See block content schemas."},"user_id":{"type":"string","format":"uuid","description":"ID of the user who created this block.","example":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234"},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the block was created.","example":"2024-01-15T10:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","description":"Timestamp when the block was last modified.","example":"2024-01-20T14:45:00.000Z"}},"example":{"id":"blk_d4e5f6a7-b8c9-0123-def1-234567890123","type":"text","variant":"heading","title":null,"content":{"heading":"Welcome to JavaScript","paragraph_1":"<p>In this lesson, you'll learn the fundamentals of JavaScript programming.</p>","options":{"headingSize":"large"}},"user_id":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234","created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"}},"BlockCreate":{"type":"object","description":"Create a new content block.\n\nThe `content` structure depends on the block `type`. See the Block Content Schemas section for detailed structures for each type, or use `GET /blocks/defaults` to get real examples.","properties":{"type":{"type":"string","description":"Block type determines the content structure required.","enum":["slide_intro","separator","text","image","audio","video","embed","pdf","callout","list","table","accordion","tabs","flashcards","timeline","flow","interactive_image","web_simulation","scene","resources","assessment","fill_in_blank","matching","click_on_image","drag_and_drop","success_meter","categorization","sorting","open_response","navigation_button","reactions","time_requirements"]},"variant":{"type":"string","default":"heading","description":"Block variant for types with multiple layouts. If omitted, the API uses the default variant from blockConfig.ts for the selected type.","example":"heading"},"content":{"type":"object","description":"Block content - see specific content schemas by block type."},"position":{"oneOf":[{"type":"integer","minimum":0},{"type":"string","enum":["end"]}],"description":"Position in the slide (0-indexed integer) or 'end' to append.","example":0}},"required":["type"]},"BlockUpdate":{"type":"object","description":"Update an existing block in place. Optionally change its variant without recreating the block or losing its content and comments. Use `content` to replace the full block content, or `content_patch` to deep-merge partial changes into the existing content. When both are provided, `content` wins.","properties":{"variant":{"type":"string","description":"Optional supported variant of the existing block type; see /blocks/defaults. For text, heading and subheading display only the title; use heading_with_paragraph or subheading_with_paragraph to also display and translate body text. Omit to keep the current variant. Linked library blocks cannot be switched through this endpoint.","example":"heading_with_paragraph"},"content":{"type":"object","description":"Full replacement block content. Structure depends on block type."},"content_patch":{"type":"object","description":"Partial content patch. Objects are merged recursively; arrays and scalar values are replaced. Useful for updating `content.format.paddingTop` or `content.settings.completionMode` without resending cards/questions."}},"examples":{"changeVariant":{"summary":"Display an existing heading and its paragraph without recreating the block","value":{"variant":"heading_with_paragraph"}},"replaceContent":{"summary":"Replace full content","value":{"content":{"heading":"Updated Heading","paragraph_1":"<p>Updated content here.</p>"}}},"patchSettings":{"summary":"Patch format and completion settings","value":{"content_patch":{"format":{"paddingTop":32,"textAlign":"center"},"settings":{"completionMode":"completed"}}}}}},"CourseImportRequest":{"type":"object","description":"Single payload to create a full course tree (course + sections + variants + slides + blocks + checkpoints). Payloads returned by `GET /courses/{courseId}/full` can be edited and posted here.","properties":{"course":{"allOf":[{"$ref":"#/components/schemas/CourseCreate"},{"type":"object","properties":{"status":{"type":"string","example":"draft"}}}],"description":"Top-level course attributes. Imports stay personal for personal OAuth or are attached to the token workspace; request-supplied `workspace_id` is ignored."},"sections":{"type":"array","description":"Optional section list. Use `key` to reference sections from slides and checkpoints.","items":{"type":"object","properties":{"key":{"type":"string","description":"Client-defined stable key (e.g. `intro`) used by slide.section_key.","example":"core"},"source_id":{"type":"string","format":"uuid","description":"Optional original section ID from a full-course export. Ignored except as a reference alias during import."},"title":{"type":"string","example":"Core Concepts"},"description":{"type":"string","example":"Main concepts every learner must understand."},"icon":{"type":"string","example":"book-open"},"cover_image":{"type":"string","nullable":true},"order_index":{"type":"integer","example":0}},"required":["title"]}},"variants":{"type":"array","description":"Adaptive learning variants. Slides reference variants with `variant_keys`; checkpoints unlock variants with `unlock_variant_keys` in rules.","items":{"type":"object","properties":{"key":{"type":"string","example":"variant_fast_track"},"source_id":{"type":"string","format":"uuid","description":"Optional original variant ID from a full-course export."},"label":{"type":"string","example":"Fast Track"},"description":{"type":"string","nullable":true},"is_required":{"type":"boolean","example":false},"details":{"type":"object","example":{"color":"#2563eb"}},"order_index":{"type":"integer","example":0}},"required":["label"]}},"slides":{"type":"array","description":"Slides to create, each with an optional block list.","items":{"type":"object","properties":{"key":{"type":"string","description":"Optional stable slide key from a full-course export.","example":"slide_welcome"},"source_id":{"type":"string","format":"uuid","description":"Optional original slide ID from a full-course export."},"title":{"type":"string","example":"Welcome"},"slide_type":{"type":"string","description":"Slide type. Defaults to `content`.","example":"content"},"section_key":{"type":"string","nullable":true,"description":"Reference to a section `key` in the `sections` array.","example":"core"},"order_index":{"type":"integer","example":0},"content":{"$ref":"#/components/schemas/SlideContent","description":"Slide-level content/settings, including optional, show_in_toc, hide_in_navigation and layoutGroups. The three flags are ignored while variants are assigned. Full-course exports use block keys in layoutGroups.blockIds; import remaps them to new block IDs."},"variant_keys":{"type":"array","nullable":true,"description":"Variant keys that gate this slide. Empty or omitted means the slide is core content.","items":{"type":"string"},"example":["variant_fast_track"]},"blocks":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Optional stable block key used by slide layout groups and checkpoint conditions.","example":"block_intro_text"},"source_id":{"type":"string","format":"uuid","nullable":true,"description":"Optional original block ID from a full-course export."},"title":{"type":"string","nullable":true,"example":"Intro text"},"type":{"type":"string","enum":["slide_intro","separator","text","image","audio","video","embed","pdf","callout","list","table","accordion","tabs","flashcards","timeline","flow","interactive_image","web_simulation","scene","resources","assessment","fill_in_blank","matching","click_on_image","drag_and_drop","success_meter","categorization","sorting","open_response","navigation_button","reactions","time_requirements"],"example":"text"},"variant":{"type":"string","example":"heading"},"content":{"type":"object"},"position":{"oneOf":[{"type":"integer","minimum":0},{"type":"string","enum":["end"]}],"example":0}},"required":["type"]}}},"required":["title"]}},"checkpoints":{"type":"array","description":"Adaptive learning checkpoints. Conditions should reference blocks with `block_key`; rules should reference variants with `unlock_variant_keys`.","items":{"type":"object","properties":{"key":{"type":"string","example":"checkpoint_after_intro"},"source_id":{"type":"string","format":"uuid","description":"Optional original checkpoint ID from a full-course export."},"title":{"type":"string","example":"Readiness Check"},"section_key":{"type":"string","nullable":true,"example":"core"},"order_index":{"type":"integer","example":2},"rules":{"type":"array","items":{"type":"object"},"example":[{"id":"rule_1","conditions":[{"block_key":"block_quiz","field":"percentage","operator":">=","value":80}],"unlock_variant_keys":["variant_fast_track"]}]}}}}},"required":["course"],"example":{"course":{"title":"Onboarding Essentials","description":"Get learners operational in less than 10 minutes.","default_locale":"fr"},"sections":[{"key":"core","title":"Core Concepts","order_index":0}],"variants":[{"key":"variant_fast_track","label":"Fast Track","is_required":false,"order_index":0}],"slides":[{"key":"slide_welcome","title":"Welcome","slide_type":"content","section_key":"core","order_index":0,"variant_keys":null,"blocks":[{"key":"block_intro","type":"slide_intro","variant":"default","content":{"title":"Welcome to Onboarding Essentials","duration":180,"objectives":["Understand the key workflow","Complete a short validation check"]},"position":0},{"key":"block_quiz","type":"assessment","variant":"assessment_stack","content":{"title":"Readiness Check","description":"Validate the key workflow before continuing."},"position":1}]}],"checkpoints":[{"key":"checkpoint_readiness","title":"Readiness Check","section_key":"core","order_index":1,"rules":[{"id":"rule_1","conditions":[{"block_key":"block_quiz","field":"percentage","operator":">=","value":80}],"unlock_variant_keys":["variant_fast_track"]}]}]}},"CourseImportResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"course_id":{"type":"string","format":"uuid"},"sections_created":{"type":"integer","example":1},"variants_created":{"type":"integer","example":1},"slides_created":{"type":"integer","example":1},"blocks_created":{"type":"integer","example":2},"checkpoints_created":{"type":"integer","example":1}},"required":["course_id","sections_created","variants_created","slides_created","blocks_created","checkpoints_created"]}},"required":["success","data"]},"CourseFullExportResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/CourseImportRequest"}},"required":["success","data"]},"TranslationUnit":{"type":"object","required":["id","type"],"additionalProperties":false,"properties":{"id":{"type":"string","minLength":1,"description":"Keep the exported ID: label key, blockId.fieldKey, course.field, section.ID.title, or slide.ID.title."},"type":{"type":"string","enum":["system_labels","content","general"],"description":"Keep the exported group; IDs are unique within each group."},"format":{"type":"string","enum":["text","html"],"description":"How to interpret the text. Preserve HTML tags, attributes, entities and placeholders when translating."},"source":{"type":"string","description":"Original text or HTML, preserved verbatim. Do not translate this field."},"target":{"type":"string","description":"Translated text or HTML. Omitted, empty or whitespace-only targets leave existing translations unchanged."},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"Keep the exported source fingerprint. If supplied with a non-empty target, import returns 409 before writes when the source changed or was removed. Optional for direct updates."},"note":{"type":"string","description":"Context for the translator; ignored during import."}}},"TranslationDocument":{"type":"object","required":["units"],"additionalProperties":false,"properties":{"schemaVersion":{"type":"integer","enum":[1],"default":1},"courseId":{"type":"string","format":"uuid","description":"If supplied, must match the course in the request path."},"locale":{"type":"string","description":"If supplied, must match the locale query parameter."},"units":{"type":"array","items":{"$ref":"#/components/schemas/TranslationUnit"}},"metadata":{"type":"object","description":"Export metadata; ignored during import.","properties":{"type":{"type":"string","enum":["all","system_labels","content","general"]},"exportedAt":{"type":"string","format":"date-time"}}}},"example":{"schemaVersion":1,"locale":"fr","units":[{"id":"course.description","type":"general","format":"html","source":"<p>Read <a href=\"https://example.com\">the guide</a>.</p>","target":"<p>Lisez <a href=\"https://example.com\">le guide</a>.</p>"}]}},"XliffJsonExport":{"type":"object","required":["xliff","filename","metadata"],"properties":{"xliff":{"type":"string","description":"XLIFF XML document; only returned with format=xliff-json."},"filename":{"type":"string"},"metadata":{"type":"object","properties":{"courseId":{"type":"string","format":"uuid"},"locale":{"type":"string"},"type":{"type":"string"},"xliffVersion":{"type":"string","enum":["1.2","2.0","2.1"]},"exportedAt":{"type":"string","format":"date-time"}}}}},"MediaContent":{"type":"object","properties":{"url":{"type":"string"},"type":{"type":"string","enum":["image","video","audio"]},"width":{"type":"number"},"height":{"type":"number"},"alt":{"type":"string"},"caption":{"type":"string"},"position":{"type":"string","enum":["left","center","right","full_card"]},"verticalAlign":{"type":"string","enum":["top","middle","bottom"]},"clickToEnlarge":{"type":"boolean"}},"additionalProperties":false,"description":"Media content structure (for Flow and Flashcards)"},"ImageContent":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"caption":{"type":"string"},"width":{"type":["number","string"]},"height":{"type":["number","string"]},"position":{"type":"string","enum":["left","center","right","full_card"]},"verticalAlign":{"type":"string","enum":["top","middle","bottom"]},"clickToEnlarge":{"type":"boolean"}},"required":["src"],"additionalProperties":false,"description":"Image content structure"},"AccordionTabItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"icon":{"type":"string"}},"required":["title","content"],"additionalProperties":false,"description":"Accordion/Tabs item"},"Flashcard":{"type":"object","properties":{"id":{"type":"string"},"front":{"type":"object","properties":{"media":{"anyOf":[{"$ref":"#/components/schemas/MediaContent"},{"type":"null"}]},"content":{"type":"string"},"tipColor":{"type":"string","enum":["dark","light"]}},"required":["content"],"additionalProperties":false},"back":{"type":"object","properties":{"media":{"anyOf":[{"$ref":"#/components/schemas/MediaContent"},{"type":"null"}]},"content":{"type":"string"},"tipColor":{"type":"string","enum":["dark","light"]}},"required":["content"],"additionalProperties":false}},"required":["id","front","back"],"additionalProperties":false,"description":"Flashcard"},"FlowStep":{"type":"object","properties":{"media":{"anyOf":[{"$ref":"#/components/schemas/MediaContent"},{"type":"null"}]},"title":{"type":"string"},"content":{"type":"string"}},"required":["content"],"additionalProperties":false,"description":"Flow step"},"FlowIntroOutro":{"type":"object","properties":{"media":{"anyOf":[{"$ref":"#/components/schemas/MediaContent"},{"type":"null"}]},"content":{"type":"string"},"startButtonText":{"type":"string"},"completionMessage":{"type":"string"}},"required":["content"],"additionalProperties":false,"description":"Flow intro/outro"},"TimelineEvent":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string"},"image":{"anyOf":[{"$ref":"#/components/schemas/ImageContent"},{"type":"null"}]},"content":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"description":"Timeline event"},"ResourceItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["link","file"]},"url":{"type":"string"},"fileUrl":{"type":"string"},"fileName":{"type":"string"},"icon":{"type":"string"}},"required":["id","title","description","type","icon"],"additionalProperties":false,"description":"Resource item"},"InteractiveImageHotspot":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["marker","area"]},"icon":{"type":"string"},"tooltip":{"type":"string"},"content":{"$ref":"#/components/schemas/HotspotContent"},"position":{"$ref":"#/components/schemas/HotspotPosition"},"leftPercent":{"type":"number"},"topPercent":{"type":"number"},"rightPercent":{"type":"number"},"bottomPercent":{"type":"number"}},"required":["id","content","position"],"additionalProperties":false,"description":"Interactive image hotspot"},"HotspotContent":{"type":"object","properties":{"text":{"type":"string"},"icon":{"type":"string"},"tooltip":{"type":"string"},"audio":{"type":["string","null"]},"image":{"anyOf":[{"$ref":"#/components/schemas/MediaContent"},{"type":"null"}]},"video":{"type":["string","null"]},"media":{"anyOf":[{"$ref":"#/components/schemas/MediaContent"},{"type":"null"}]}},"required":["text"],"additionalProperties":false,"description":"Hotspot content (for Interactive Image block)"},"HotspotPosition":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false,"description":"Hotspot position"},"ClickOnImageHotspot":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"topPercent":{"type":"number"},"leftPercent":{"type":"number"},"rightPercent":{"type":"number"},"bottomPercent":{"type":"number"},"feedback":{"type":"string"},"isCorrect":{"type":"boolean"}},"required":["id","name","topPercent","leftPercent","rightPercent","bottomPercent","feedback","isCorrect"],"additionalProperties":false,"description":"Click-on-image hotspot"},"MatchingItem":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["text","image"]},"content":{"type":"string"},"alt":{"type":"string"}},"required":["id","type","content"],"additionalProperties":false,"description":"Matching item"},"MatchingPair":{"type":"object","properties":{"leftId":{"type":"string"},"rightId":{"type":"string"},"explanation":{"type":"string"}},"required":["leftId","rightId","explanation"],"additionalProperties":false,"description":"Matching pair"},"SortingItem":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["text","image"]},"textContent":{"type":"string"},"imageContent":{"type":"string"},"alt":{"type":"string"}},"required":["id","type"],"additionalProperties":false,"description":"Sorting item"},"BlankDefinition":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["text","list"]},"correctAnswers":{"type":"array","items":{"type":"string"}},"options":{"type":"array","items":{"type":"string"}},"caseSensitive":{"type":"boolean"}},"required":["id","type","correctAnswers"],"additionalProperties":false,"description":"Fill-in-blank definition"},"AssessmentOption":{"type":"object","properties":{"label":{"type":"string"},"points":{"type":"number"},"rationale":{"type":"string"}},"required":["label","points","rationale"],"additionalProperties":false,"description":"Assessment question option"},"AssessmentQuestion":{"type":"object","properties":{"id":{"type":"string"},"prompt":{"type":"string"},"choiceDisplay":{"type":"string","enum":["rows","columns"]},"options":{"type":"array","items":{"$ref":"#/components/schemas/AssessmentOption"}}},"required":["id","prompt","options"],"additionalProperties":false,"description":"Assessment question"},"QuizAssessmentChoice":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"correct":{"type":"boolean"},"hint":{"type":"string"},"image":{"anyOf":[{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"caption":{"type":"string"},"position":{"type":"string","enum":["left","center","right"]},"verticalAlign":{"type":"string","enum":["top","middle","bottom"]},"height":{"type":["number","string"]},"mediaId":{"type":["string","null"]}},"required":["src"],"additionalProperties":false},{"type":"null"}]}},"required":["id","text","correct"],"additionalProperties":false,"description":"Quiz assessment choice (for Assessment block)"},"QuizAssessmentQuestion":{"anyOf":[{"$ref":"#/components/schemas/QuizAssessmentChoiceQuestion"},{"$ref":"#/components/schemas/QuizAssessmentNumericalQuestion"},{"$ref":"#/components/schemas/QuizAssessmentStringQuestion"}],"description":"Quiz assessment question (for Assessment block)"},"QuizAssessmentChoiceQuestion":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"solution":{"type":"string"},"type":{"type":"string","enum":["MultipleChoice","MultipleResponse"]},"feedback":{"$ref":"#/components/schemas/QuizAssessmentFeedback"},"choiceDisplay":{"type":"string","enum":["rows","columns"]},"choices":{"type":"array","items":{"$ref":"#/components/schemas/QuizAssessmentChoice"}}},"required":["choices","id","title","type"],"additionalProperties":false,"description":"Quiz assessment choice question (for Assessment block)"},"QuizAssessmentFeedback":{"type":"object","properties":{"correct":{"$ref":"#/components/schemas/QuizAssessmentFeedbackContent"},"incorrect":{"$ref":"#/components/schemas/QuizAssessmentFeedbackContent"},"try_again":{"$ref":"#/components/schemas/QuizAssessmentFeedbackContent"}},"additionalProperties":false},"QuizAssessmentFeedbackContent":{"type":"object","properties":{"text":{"type":"string"},"image":{"type":"string"}},"additionalProperties":false},"QuizAssessmentNumericalQuestion":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"solution":{"type":"string"},"type":{"type":"string","const":"NumericalResponse"},"feedback":{"$ref":"#/components/schemas/QuizAssessmentFeedback"},"answer":{"type":"number"},"tolerance":{"type":"string"}},"required":["answer","id","title","type"],"additionalProperties":false,"description":"Quiz assessment numerical question (for Assessment block)"},"QuizAssessmentStringQuestion":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"solution":{"type":"string"},"type":{"type":"string","const":"StringResponse"},"feedback":{"$ref":"#/components/schemas/QuizAssessmentFeedback"},"answer":{"type":"string"},"additionalAnswers":{"type":"array","items":{"type":"string"}},"caseSensitive":{"type":"boolean"}},"required":["answer","id","title","type"],"additionalProperties":false,"description":"Quiz assessment string question (for Assessment block)"},"QuizAssessmentProblemSettings":{"type":"object","properties":{"shuffleAnswers":{"type":"boolean"},"maxAttempts":{"type":["number","null"]},"showAnswer":{"type":"string"},"weight":{"type":["number","null"]}},"additionalProperties":false,"description":"Quiz assessment problem settings (for Assessment block)"},"GradingConfig":{"type":"object","properties":{"partialCredit":{"type":"boolean"},"weight":{"type":"number"},"maxAttempts":{"type":["number","null"]},"caseSensitive":{"type":"boolean"},"max_attempts":{"type":"number"},"showAnswer":{"type":"string"}},"additionalProperties":false,"description":"Grading configuration for assessment blocks"},"BlockFormat":{"type":"object","properties":{"width":{"type":"number","description":"Width percentage (0-100)"},"contentMaxWidth":{"type":"number","description":"Content max width (1-5 scale)"},"paddingTop":{"type":"number","description":"Top padding in pixels"},"paddingBottom":{"type":"number","description":"Bottom padding in pixels"},"paddingLeft":{"type":"number","description":"Left padding in pixels"},"paddingRight":{"type":"number","description":"Right padding in pixels"},"paddingLinked":{"type":"boolean","description":"Legacy flag for older top/bottom linked padding controls"},"marginTop":{"type":"number","description":"Internal top margin around the styled block surface in pixels"},"marginBottom":{"type":"number","description":"Internal bottom margin around the styled block surface in pixels"},"marginLeft":{"type":"number","description":"Internal left margin around the styled block surface in pixels"},"marginRight":{"type":"number","description":"Internal right margin around the styled block surface in pixels"},"borderRadius":{"type":["number","string"],"description":"Border radius for the styled block surface"},"textAlign":{"$ref":"#/components/schemas/TextAlign","description":"Text alignment using logical properties"},"backgroundType":{"$ref":"#/components/schemas/BackgroundType","description":"Background type"},"backgroundColor":{"type":"string","description":"Background color (hex or CSS var)"},"accentColor":{"type":"string","description":"Accent color (hex or CSS var)"},"gap":{"type":"number","description":"Gap between elements in pixels"},"height":{"type":"number","description":"Optional height in pixels"},"backgroundImageSrc":{"type":"string","description":"Background image URL (when backgroundType is IMAGE)"},"backgroundSize":{"type":"string","description":"Background image size"},"backgroundPosition":{"type":"string","description":"Background image position"},"backgroundRepeat":{"type":"string","description":"Background image repeat"}},"required":["width","contentMaxWidth","paddingTop","paddingBottom","paddingLinked","textAlign","backgroundType","backgroundColor","accentColor","gap"],"additionalProperties":false,"description":"Default block format configuration"},"TextAlign":{"type":"string","enum":["start","center","end"],"description":"Alignment options (logical properties for RTL support)"},"BackgroundType":{"type":"string","enum":["LIGHT","DARK","THEME","COLOR","IMAGE"],"description":"Background type options"},"TextBlockContent":{"type":"object","properties":{"heading":{"type":"string"},"paragraph_1":{"type":"string"},"paragraph_2":{"type":"string"},"paragraph_3":{"type":"string"},"paragraph_4":{"type":"string"},"options":{"$ref":"#/components/schemas/TextBlockOptions"}},"additionalProperties":false,"description":"Text block content structure"},"TextBlockOptions":{"type":"object","properties":{"headingSize":{"type":"string","enum":["small","medium","large"]},"headingFormat":{"type":"string","enum":["simple","numbered","icon"]},"columnCount":{"type":"number","enum":[2,3,4]}},"additionalProperties":false,"description":"Text block content options"},"ImageBlockContent":{"type":"object","properties":{"text":{"type":"string"},"images":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ImageContent"}},"options":{"$ref":"#/components/schemas/ImageBlockOptions"},"format":{"type":"object","properties":{"overlayColor":{"type":"string"},"overlayOpacity":{"type":"number"}},"additionalProperties":false}},"additionalProperties":false,"description":"Image block content structure"},"ImageBlockOptions":{"type":"object","properties":{"box_shadow":{"type":"boolean"},"grid_columns":{"type":"number"},"show_caption":{"type":"boolean"},"carousel_loop":{"type":"boolean"},"carousel_autoplay":{"type":"boolean"},"carousel_autoplay_delay":{"type":"number"},"carousel_show_navigation":{"type":"boolean"},"carousel_show_pagination":{"type":"boolean"},"carousel_effect":{"type":"string"}},"additionalProperties":false,"description":"Image block options"},"VideoBlockContent":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"caption":{"type":"string"},"poster":{"type":"string"},"subtitles":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"label":{"type":"string"},"language":{"type":"string"}},"required":["src","label","language"],"additionalProperties":false}},"aspectRatio":{"type":"number"},"quality":{"type":"string"},"startTime":{"type":"number"},"endTime":{"type":"number"},"autoplay":{"type":"boolean"},"controls":{"type":"boolean"},"loop":{"type":"boolean"},"muted":{"type":"boolean"},"provider":{"type":"string","enum":["youtube","vimeo","upload"]},"color":{"type":"string"},"showTitle":{"type":"boolean"},"showByline":{"type":"boolean"},"showPortrait":{"type":"boolean"},"showPlaybar":{"type":"boolean"},"showVolume":{"type":"boolean"},"showSpeed":{"type":"boolean"},"allowFullscreen":{"type":"boolean"},"allowPip":{"type":"boolean"},"enableKeyboard":{"type":"boolean"},"showCaptionsByDefault":{"type":"boolean"},"preload":{"type":"string","enum":["none","metadata","auto"]},"settings":{"$ref":"#/components/schemas/VideoBlockSettings"}},"additionalProperties":false},"VideoBlockSettings":{"type":"object","properties":{"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false,"description":"Video block content structure"},"AudioBlockContent":{"type":"object","properties":{"src":{"type":"string"},"title":{"type":"string"},"caption":{"type":"string"},"transcript":{"type":"string"},"autoplay":{"type":"boolean"},"showTitle":{"type":"boolean"},"showProgress":{"type":"boolean"},"showSpeed":{"type":"boolean"},"showVisualization":{"type":"boolean"},"loop":{"type":"boolean"},"settings":{"$ref":"#/components/schemas/AudioBlockSettings"}},"additionalProperties":false},"AudioBlockSettings":{"type":"object","properties":{"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false,"description":"Audio block content structure"},"FlowBlockContent":{"type":"object","properties":{"intro":{"$ref":"#/components/schemas/FlowIntroOutro"},"outro":{"$ref":"#/components/schemas/FlowIntroOutro"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/FlowStep"}},"format":{"type":"object","properties":{"width":{"type":"number","description":"Width percentage (0-100)"},"contentMaxWidth":{"type":"number","description":"Content max width (1-5 scale)"},"paddingTop":{"type":"number","description":"Top padding in pixels"},"paddingBottom":{"type":"number","description":"Bottom padding in pixels"},"paddingLeft":{"type":"number","description":"Left padding in pixels"},"paddingRight":{"type":"number","description":"Right padding in pixels"},"paddingLinked":{"type":"boolean","description":"Legacy flag for older top/bottom linked padding controls"},"marginTop":{"type":"number","description":"Internal top margin around the styled block surface in pixels"},"marginBottom":{"type":"number","description":"Internal bottom margin around the styled block surface in pixels"},"marginLeft":{"type":"number","description":"Internal left margin around the styled block surface in pixels"},"marginRight":{"type":"number","description":"Internal right margin around the styled block surface in pixels"},"borderRadius":{"type":["number","string"],"description":"Border radius for the styled block surface"},"textAlign":{"$ref":"#/components/schemas/TextAlign","description":"Text alignment using logical properties"},"backgroundType":{"$ref":"#/components/schemas/BackgroundType","description":"Background type"},"backgroundColor":{"type":"string","description":"Background color (hex or CSS var)"},"accentColor":{"type":"string","description":"Accent color (hex or CSS var)"},"gap":{"type":"number","description":"Gap between elements in pixels"},"height":{"type":"number","description":"Optional height in pixels"},"backgroundImageSrc":{"type":"string","description":"Background image URL (when backgroundType is IMAGE)"},"backgroundSize":{"type":"string","description":"Background image size"},"backgroundPosition":{"type":"string","description":"Background image position"},"backgroundRepeat":{"type":"string","description":"Background image repeat"}},"additionalProperties":false},"settings":{"$ref":"#/components/schemas/FlowBlockSettings"}},"additionalProperties":false,"description":"Flow block content structure"},"FlowBlockSettings":{"type":"object","properties":{"height":{"type":["number","null"],"description":"Fixed card height in pixels on desktop (minimum rendered height: 200px). Omit or use null for auto height. Mobile always uses auto height."},"allowSkip":{"type":"boolean"},"autoPlayAudio":{"type":"boolean"},"showNavigation":{"type":"boolean"},"showNextButton":{"type":"boolean"},"navigationStyle":{"type":"string"},"showProgressBar":{"type":"boolean"},"showStepNumbers":{"type":"boolean"},"transitionEffect":{"type":"string"},"showPreviousButton":{"type":"boolean"},"defaultNextButtonText":{"type":"string"},"defaultPreviousButtonText":{"type":"string"},"showIntro":{"type":"boolean"},"showOutro":{"type":"boolean"},"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false,"description":"Flow block settings"},"TimelineBlockContent":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TimelineEvent"}},"format":{"type":"object","properties":{"width":{"type":"number","description":"Width percentage (0-100)"},"contentMaxWidth":{"type":"number","description":"Content max width (1-5 scale)"},"paddingTop":{"type":"number","description":"Top padding in pixels"},"paddingBottom":{"type":"number","description":"Bottom padding in pixels"},"paddingLeft":{"type":"number","description":"Left padding in pixels"},"paddingRight":{"type":"number","description":"Right padding in pixels"},"paddingLinked":{"type":"boolean","description":"Legacy flag for older top/bottom linked padding controls"},"marginTop":{"type":"number","description":"Internal top margin around the styled block surface in pixels"},"marginBottom":{"type":"number","description":"Internal bottom margin around the styled block surface in pixels"},"marginLeft":{"type":"number","description":"Internal left margin around the styled block surface in pixels"},"marginRight":{"type":"number","description":"Internal right margin around the styled block surface in pixels"},"borderRadius":{"type":["number","string"],"description":"Border radius for the styled block surface"},"textAlign":{"$ref":"#/components/schemas/TextAlign","description":"Text alignment using logical properties"},"backgroundType":{"$ref":"#/components/schemas/BackgroundType","description":"Background type"},"backgroundColor":{"type":"string","description":"Background color (hex or CSS var)"},"accentColor":{"type":"string","description":"Accent color (hex or CSS var)"},"gap":{"type":"number","description":"Gap between elements in pixels"},"height":{"type":"number","description":"Optional height in pixels"},"backgroundImageSrc":{"type":"string","description":"Background image URL (when backgroundType is IMAGE)"},"backgroundSize":{"type":"string","description":"Background image size"},"backgroundPosition":{"type":"string","description":"Background image position"},"backgroundRepeat":{"type":"string","description":"Background image repeat"}},"additionalProperties":false},"settings":{"$ref":"#/components/schemas/TimelineBlockSettings"}},"additionalProperties":false,"description":"Timeline block content structure"},"TimelineBlockSettings":{"type":"object","properties":{"layout":{"type":"string","enum":["vertical","compact","horizontal_cards"]},"displayMode":{"type":"string","enum":["expandable","static"]},"completionMode":{"type":"string","enum":["viewed","tried","completed"]},"showConnectors":{"type":"boolean"},"connectorColor":{"type":"string"}},"additionalProperties":false,"description":"Timeline block settings"},"FlashcardsBlockContent":{"type":"object","properties":{"cards":{"type":"array","items":{"$ref":"#/components/schemas/Flashcard"}},"settings":{"$ref":"#/components/schemas/FlashcardsBlockSettings"}},"additionalProperties":false,"description":"Flashcards block content structure"},"FlashcardsBlockSettings":{"type":"object","properties":{"height":{"type":["string","number"]},"gridColumns":{"type":"number"},"completionMode":{"type":"string","enum":["viewed","tried","completed"]},"allowShuffle":{"type":"boolean"},"showProgress":{"type":"boolean"},"flipDirection":{"type":"string","enum":["horizontal","vertical"]},"autoFlip":{"type":"boolean"},"autoFlipDelay":{"type":"number"}},"additionalProperties":false,"description":"Flashcards block settings"},"AccordionBlockContent":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AccordionTabItem"}},"options":{"$ref":"#/components/schemas/AccordionTabsOptions"},"settings":{"type":"object","properties":{"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false}},"additionalProperties":false,"description":"Accordion block content structure"},"AccordionTabsOptions":{"type":"object","properties":{"type":{"type":"string","enum":["single","multiple"]},"defaultTab":{"type":"number"},"tabsDisplay":{"type":"string","enum":["compact","full"]},"tabHeight":{"type":["number","null"]},"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false,"description":"Accordion/Tabs block options"},"TabsBlockContent":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AccordionTabItem"}},"options":{"$ref":"#/components/schemas/AccordionTabsOptions"}},"additionalProperties":false,"description":"Tabs block content structure"},"AssessmentBlockContent":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"questions":{"type":"array","items":{"$ref":"#/components/schemas/QuizAssessmentQuestion"}},"question_bank":{"$ref":"#/components/schemas/AssessmentQuestionBank"},"problemSettings":{"$ref":"#/components/schemas/QuizAssessmentProblemSettings"},"settings":{"$ref":"#/components/schemas/AssessmentBlockSettings"},"gradingMode":{"type":"string","enum":["graded","ungraded"]},"grade_required":{"type":"number"},"weight":{"type":["number","null"]},"display_intro_page":{"type":"boolean"},"display_summary_page":{"type":"boolean"},"show_navigation":{"type":"boolean"},"show_question_number":{"type":"boolean"},"display_mode":{"type":"string","enum":["stacks","inline"]},"format":{"$ref":"#/components/schemas/BlockFormat"},"grader_assignment":{"anyOf":[{"type":"object","properties":{"grader_id":{"type":"string"},"individual_weight":{"type":"number"}},"additionalProperties":false},{"type":"null"}]}},"additionalProperties":false,"description":"Assessment block content structure"},"AssessmentQuestionBank":{"type":"object","properties":{"mode":{"type":"string","enum":["manual","random"]},"rules":{"type":"array","items":{"$ref":"#/components/schemas/AssessmentQuestionBankRule"}},"question_bank_pools":{"anyOf":[{"type":"object","additionalProperties":{}},{"type":"array","items":{}}]}},"additionalProperties":false},"AssessmentQuestionBankRule":{"type":"object","properties":{"id":{"type":"string"},"library_id":{"type":"string"},"library_name":{"type":"string"},"group_ids":{"type":"array","items":{"type":"string"}},"selected_question_ids":{"type":"array","items":{"type":"string"}},"question_pool_mode":{"type":"string","enum":["all","selected"]},"draw_count":{"type":"number"},"pool_id":{"type":"string"},"questions":{"type":"array","items":{"$ref":"#/components/schemas/QuizAssessmentQuestion"}}},"additionalProperties":{}},"AssessmentBlockSettings":{"type":"object","properties":{"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false},"AssessmentCompletionModeSetting":{"type":"string","enum":["viewed","tried","completed"]},"FillInBlankBlockContent":{"type":"object","properties":{"title":{"type":"string"},"instructions":{"type":"string"},"passage":{"type":"string"},"blanks":{"type":"array","items":{"$ref":"#/components/schemas/BlankDefinition"}},"solution":{"type":"string"},"grade_required":{"type":"number"},"settings":{"$ref":"#/components/schemas/FillInBlankSettings"},"grading":{"$ref":"#/components/schemas/GradingConfig"}},"additionalProperties":false,"description":"Fill-in-blank block content structure"},"FillInBlankSettings":{"type":"object","properties":{"showProgress":{"type":"boolean"},"showInstructions":{"type":"boolean"},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"Fill-in-blank block settings"},"MatchingBlockContent":{"type":"object","properties":{"title":{"type":"string"},"instructions":{"type":"string"},"leftColumn":{"type":"array","items":{"$ref":"#/components/schemas/MatchingItem"}},"rightColumn":{"type":"array","items":{"$ref":"#/components/schemas/MatchingItem"}},"correctMatches":{"type":"array","items":{"$ref":"#/components/schemas/MatchingPair"}},"idMode":{"type":"string","const":"stable"},"nextLeftId":{"type":"number"},"nextRightId":{"type":"number"},"leftColumnTitle":{"type":"string"},"rightColumnTitle":{"type":"string"},"solution":{"type":"string"},"grade_required":{"type":"number"},"settings":{"$ref":"#/components/schemas/MatchingBlockSettings"},"grading":{"$ref":"#/components/schemas/GradingConfig"}},"additionalProperties":false,"description":"Matching block content structure"},"MatchingBlockSettings":{"type":"object","properties":{"showProgress":{"type":"boolean"},"showInstructions":{"type":"boolean"},"shuffleLeft":{"type":"boolean"},"shuffleRight":{"type":"boolean"},"allowMultipleConnections":{"type":"boolean"},"columnsRatio":{"type":"string"},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"Matching block settings"},"ClickOnImageBlockContent":{"type":"object","properties":{"title":{"type":"string"},"instructions":{"type":"string"},"imageUrl":{"type":"string"},"imageAlt":{"type":"string"},"hotspots":{"type":"array","items":{"$ref":"#/components/schemas/ClickOnImageHotspot"}},"solution":{"type":"string"},"grade_required":{"type":"number"},"settings":{"$ref":"#/components/schemas/ClickOnImageSettings"},"grading":{"$ref":"#/components/schemas/GradingConfig"}},"additionalProperties":false,"description":"Click-on-image block content structure"},"ClickOnImageSettings":{"type":"object","properties":{"showInstructions":{"type":"boolean"},"maxUserAreas":{"type":"number"},"highlightCorrectOnComplete":{"type":"boolean"},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"Click-on-image block settings"},"InteractiveImageBlockContent":{"type":"object","properties":{"imageUrl":{"type":"string"},"imageAlt":{"type":"string"},"hotspots":{"type":"array","items":{"$ref":"#/components/schemas/InteractiveImageHotspot"}},"settings":{"type":"object","properties":{"showHotspotLabels":{"type":"boolean"},"hotSpotStyle":{"type":"string"},"hotspotStyle":{"type":"string"},"hotspotSize":{"type":["string","number"]},"hotspotColor":{"type":"string"},"showHotspotNumbers":{"type":"boolean"},"showHotspotNav":{"type":"boolean"},"clickBehavior":{"type":"string","enum":["modal","sidebar","tooltip"]},"completionMode":{"type":"string","enum":["viewed","tried","completed"]},"hotspotDisplayMode":{"type":"string","enum":["annotated","discovery"]}},"additionalProperties":false}},"additionalProperties":false,"description":"Interactive image block content structure"},"WebSimulationBlockContent":{"type":"object","properties":{"startText":{"type":"string"},"finishText":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/WebSimulationStep"}},"settings":{"$ref":"#/components/schemas/WebSimulationSettings"}},"additionalProperties":false,"description":"Web simulation block content structure"},"WebSimulationStep":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"backgroundImage":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src"],"additionalProperties":false},"areas":{"type":"array","items":{"$ref":"#/components/schemas/WebSimulationArea"}},"isEndStep":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"description":"Web simulation step"},"WebSimulationArea":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"topPercent":{"type":"number"},"leftPercent":{"type":"number"},"rightPercent":{"type":"number"},"bottomPercent":{"type":"number"},"targetStepId":{"type":"string"}},"required":["id","topPercent","leftPercent","rightPercent","bottomPercent"],"additionalProperties":false,"description":"Web simulation step area"},"WebSimulationSettings":{"type":"object","properties":{"showClickableAreas":{"type":"boolean"},"showProgress":{"type":"boolean"},"showBrowser":{"type":"boolean"},"allowFullscreen":{"type":"boolean"},"deviceType":{"type":"string","enum":["desktop","tablet","mobile"]},"areaColor":{"type":"string"},"showIntro":{"type":"boolean"},"showOutro":{"type":"boolean"},"navigationStyle":{"type":"string","enum":["hide","dots","numbers"]},"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false,"description":"Web simulation block settings"},"SuccessMeterBlockContent":{"type":"object","properties":{"assessment_title":{"type":"string"},"introduction":{"type":"string"},"core_questions":{"type":"array","items":{"$ref":"#/components/schemas/AssessmentQuestion"}},"extra_questions":{"type":"array","items":{"$ref":"#/components/schemas/AssessmentQuestion"}},"show_question_number":{"type":"boolean"},"results":{"$ref":"#/components/schemas/SuccessMeterResults"},"grade_required":{"type":"number"},"settings":{"$ref":"#/components/schemas/SuccessMeterSettings"},"grading":{"$ref":"#/components/schemas/GradingConfig"},"initial_points":{"type":"number"}},"additionalProperties":false,"description":"Success meter block content structure"},"SuccessMeterResults":{"type":"object","properties":{"high":{"type":"object","properties":{"range":{"type":"string"},"message":{"type":"string"}},"required":["range","message"],"additionalProperties":false},"medium":{"type":"object","properties":{"range":{"type":"string"},"message":{"type":"string"}},"required":["range","message"],"additionalProperties":false},"low":{"type":"object","properties":{"range":{"type":"string"},"message":{"type":"string"}},"required":["range","message"],"additionalProperties":false}},"additionalProperties":false,"description":"Success meter results configuration"},"SuccessMeterSettings":{"type":"object","properties":{"show_progress_meter":{"type":"boolean"},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"Success meter block settings"},"CategorizationBlockContent":{"type":"object","properties":{"title":{"type":"string"},"instructions":{"type":"string"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/CategorizationCategory"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/CategorizationItem"}},"solution":{"type":"string"},"grade_required":{"type":"number"},"settings":{"$ref":"#/components/schemas/CategorizationSettings"},"grading":{"$ref":"#/components/schemas/GradingConfig"}},"additionalProperties":false,"description":"Categorization block content structure"},"CategorizationCategory":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"description":"Categorization category"},"CategorizationItem":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["text","image"]},"textContent":{"type":"string"},"imageContent":{"type":"string"},"correctCategoryId":{"type":"string"},"feedback":{"type":"string"}},"required":["id","type","correctCategoryId"],"additionalProperties":false,"description":"Categorization item"},"CategorizationSettings":{"type":"object","properties":{"showInstructions":{"type":"boolean"},"shuffleItems":{"type":"boolean"},"showFeedback":{"type":"boolean"},"allowRetry":{"type":"boolean"},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"Categorization block settings"},"SortingBlockContent":{"type":"object","properties":{"title":{"type":"string"},"instructions":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/SortingItem"}},"correctOrder":{"type":"array","items":{"type":"string"}},"solution":{"type":"string"},"grade_required":{"type":"number"},"settings":{"$ref":"#/components/schemas/SortingSettings"},"grading":{"$ref":"#/components/schemas/GradingConfig"}},"additionalProperties":false,"description":"Sorting block content structure"},"SortingSettings":{"type":"object","properties":{"showInstructions":{"type":"boolean"},"shuffleItems":{"type":"boolean"},"showPositionInputs":{"type":"boolean"},"showMoveButtons":{"type":"boolean"},"direction":{"type":"string","enum":["vertical","horizontal"]},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"Sorting block settings"},"OpenResponseBlockContent":{"type":"object","properties":{"title":{"type":"string"},"prompt":{"type":"string"},"instructions":{"type":"string"},"placeholder":{"type":"string"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"modelAnswer":{"type":"string"},"rubric":{"type":"string"},"grade_required":{"type":"number"},"settings":{"type":"object","properties":{"showInstructions":{"type":"boolean"},"showCharacterCount":{"type":"boolean"},"maxCharacters":{"type":"number"},"showWordCount":{"type":"boolean"},"allowRichText":{"type":"boolean"},"showModelAnswer":{"type":"boolean"},"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false},"grading":{"$ref":"#/components/schemas/GradingConfig"}},"additionalProperties":false,"description":"Open response block content structure"},"CalloutBlockContent":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"},"icon":{"type":"string"},"type":{"type":"string","enum":["info","warning","success","error","tip","note","important","exercise"]},"iconPosition":{"type":"string","enum":["top","left","right","bottom"]},"color":{"type":"string"}},"additionalProperties":false,"description":"Callout block content structure"},"ListBlockContent":{"type":"object","properties":{"heading":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ListItem"}},"options":{"$ref":"#/components/schemas/ListBlockOptions"}},"additionalProperties":false,"description":"List block content structure"},"ListItem":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"icon":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"List item structure"},"ListBlockOptions":{"type":"object","properties":{"iconSize":{"type":"number"},"markerSize":{"type":"number"},"startNumber":{"type":"number"},"columns":{"type":"number"},"showDividers":{"type":"boolean"},"completionMode":{"type":"string","enum":["viewed","tried","completed"]}},"additionalProperties":false,"description":"List block options"},"SeparatorBlockContent":{"type":"object","properties":{"text":{"type":"string"},"shape":{"type":"string"},"extend_background":{"type":"boolean"},"flip_vertical":{"type":"boolean"},"gradient":{"type":"object","properties":{"direction":{"type":"string"}},"additionalProperties":false},"options":{"type":"object","properties":{"thickness":{"type":"number"},"opacity":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"},"top_color":{"type":"string"},"gradientEndColor":{"type":"string"},"gradientDirection":{"type":"string"},"gradientStartColor":{"type":"string"},"custom_shape_data":{"$ref":"#/components/schemas/SeparatorCustomShapeData"},"custom_shape_svg_path":{"type":"string"},"custom_shape_svg_viewbox":{"type":"string"},"custom_shape_svg_markup":{"type":"string"}},"additionalProperties":false}},"additionalProperties":false,"description":"Separator block content structure"},"SeparatorCustomShapeData":{"type":"object","properties":{"anchors":{"type":"array","items":{"$ref":"#/components/schemas/SeparatorShapePoint"}},"segments":{"type":"array","items":{"$ref":"#/components/schemas/SeparatorShapeSegment"}}},"required":["anchors","segments"],"additionalProperties":false},"SeparatorShapePoint":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false},"SeparatorShapeSegment":{"type":"object","properties":{"cp1":{"$ref":"#/components/schemas/SeparatorShapePoint"},"cp2":{"$ref":"#/components/schemas/SeparatorShapePoint"}},"required":["cp1","cp2"],"additionalProperties":false},"ResourcesBlockContent":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ResourceItem"}},"options":{"type":"object","properties":{"layout":{"type":"string","enum":["list","grid"]},"showIcons":{"type":"boolean"},"showDescriptions":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false,"description":"Resources block content structure"},"EmbedBlockContent":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"dimension":{"type":"string","enum":["auto","ratio"]},"aspectRatio":{"type":"string","enum":["16:9","4:3"]},"height":{"type":["number","string"]},"completionBehavior":{"type":"string","enum":["auto","manual"]},"gradingMode":{"type":"string","enum":["graded","ungraded"]},"grade_required":{"type":"number"},"weight":{"type":["number","null"]},"grading":{"type":"object","properties":{"weight":{"type":["number","null"]}},"additionalProperties":false},"settings":{"type":"object","properties":{"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false}},"additionalProperties":false,"description":"Embed block content structure"},"PdfBlockContent":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"height":{"type":"number"},"showDownload":{"type":"boolean"},"showPrint":{"type":"boolean"},"settings":{"$ref":"#/components/schemas/PdfBlockSettings"}},"additionalProperties":false,"description":"PDF block content structure"},"PdfBlockSettings":{"type":"object","properties":{"completionMode":{"$ref":"#/components/schemas/AssessmentCompletionModeSetting"}},"additionalProperties":false,"description":"PDF block settings"},"SlideIntroBlockContent":{"type":"object","properties":{"title":{"type":"string"},"duration":{"type":"number"},"objectives":{"type":"array","items":{"type":"string"}},"icon":{"type":"string"},"format":{"type":"object","additionalProperties":false,"properties":{"showLesson":{"type":"boolean"},"showObjectives":{"type":"boolean"},"showTableOfContent":{"type":"boolean"},"width":{"type":"number","description":"Width percentage (0-100)"},"contentMaxWidth":{"type":"number","description":"Content max width (1-5 scale)"},"paddingTop":{"type":"number","description":"Top padding in pixels"},"paddingBottom":{"type":"number","description":"Bottom padding in pixels"},"paddingLeft":{"type":"number","description":"Left padding in pixels"},"paddingRight":{"type":"number","description":"Right padding in pixels"},"paddingLinked":{"type":"boolean","description":"Legacy flag for older top/bottom linked padding controls"},"marginTop":{"type":"number","description":"Internal top margin around the styled block surface in pixels"},"marginBottom":{"type":"number","description":"Internal bottom margin around the styled block surface in pixels"},"marginLeft":{"type":"number","description":"Internal left margin around the styled block surface in pixels"},"marginRight":{"type":"number","description":"Internal right margin around the styled block surface in pixels"},"borderRadius":{"type":["number","string"],"description":"Border radius for the styled block surface"},"textAlign":{"$ref":"#/components/schemas/TextAlign","description":"Text alignment using logical properties"},"backgroundType":{"$ref":"#/components/schemas/BackgroundType","description":"Background type"},"backgroundColor":{"type":"string","description":"Background color (hex or CSS var)"},"accentColor":{"type":"string","description":"Accent color (hex or CSS var)"},"gap":{"type":"number","description":"Gap between elements in pixels"},"height":{"type":"number","description":"Optional height in pixels"},"backgroundImageSrc":{"type":"string","description":"Background image URL (when backgroundType is IMAGE)"},"backgroundSize":{"type":"string","description":"Background image size"},"backgroundPosition":{"type":"string","description":"Background image position"},"backgroundRepeat":{"type":"string","description":"Background image repeat"}}}},"additionalProperties":false,"description":"Slide intro block content structure"},"NavigationButtonBlockContent":{"type":"object","properties":{"label":{"type":"string"},"autoContinue":{"type":"boolean","description":"Automatically activate a Continue button once its enablement condition is met."},"reloadLmsPageOnFinish":{"type":"boolean","description":"Reload the containing LMS page after successfully saving and ending an embedded SCORM session."},"actionType":{"$ref":"#/components/schemas/NavigationActionType"},"targetSlideId":{"type":"string"},"externalUrl":{"type":"string"},"openInNewTab":{"type":"boolean"},"style":{"type":"string","enum":["primary","secondary","outline"]}},"additionalProperties":false,"description":"Navigation button block content structure"},"NavigationActionType":{"type":"string","enum":["next_slide","previous_slide","go_to_slide","continue","complete_course","finish_and_exit_course","external_link"],"description":"Navigation button action types"},"ReactionsBlockContent":{"type":"object","properties":{"title":{"type":"string"},"settings":{"$ref":"#/components/schemas/ReactionsBlockSettings"}},"additionalProperties":false},"ReactionsBlockSettings":{"type":"object","properties":{"completionMode":{"type":"string","enum":["viewed","tried"]},"displayMode":{"type":"string","enum":["large","compact"]},"showCommentBox":{"type":"boolean"},"hideIfNotEnabled":{"type":"boolean"},"enablementCondition":{"type":"string","enum":["no_condition","previous_block","all_previous_blocks"]}},"additionalProperties":false}}},"security":[{"BearerAuth":[]}],"paths":{"/themes":{"get":{"summary":"List accessible themes","description":"Lists system themes, themes owned by the token user, and themes shared through courses the user can access in the token workspace. Deduplicated and sorted by creation date (newest first), then ID. Requires courses:read (or api:*). Use a returned id as theme_id when creating or updating a course. Theme creation and editing are not exposed by this API.","operationId":"listThemes","tags":["Themes"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Accessible themes and pagination metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Theme"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid pagination parameters."},"401":{"description":"Missing or invalid authentication."},"403":{"description":"Insufficient scope or workspace access."},"429":{"description":"Rate limit exceeded."}}}},"/courses":{"get":{"summary":"List all courses","description":"Retrieves courses in the connected space. Personal OAuth returns only courses owned by the connected user with no workspace. Workspace connections return only currently accessible courses in that workspace; folder and collaborator permissions still apply. Requires courses:read (or api:*). Results are sorted by creation date (newest first), then ID for stable pagination. Follow pagination.totalPages to retrieve the complete list (up to 100 courses per page).","operationId":"listCourses","tags":["Courses"],"parameters":[{"name":"page","in":"query","description":"Page number for pagination (1-indexed).","schema":{"type":"integer","default":1,"minimum":1},"example":1},{"name":"limit","in":"query","description":"Number of items per page (max 100).","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"example":20}],"responses":{"200":{"description":"Successfully retrieved list of courses.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Course"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"example":{"success":true,"data":[{"id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Introduction to JavaScript","description":"Learn the fundamentals of JavaScript programming.","cover_image":"https://assets.scormstack.com/courses/js-intro/cover.jpg","user_id":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234","created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z","settings":{"navigation":{"allow_skip":false}}},{"id":"crs_f6a7b8c9-d0e1-2345-f678-90abcdef1234","title":"Advanced React Patterns","description":"Master advanced React techniques and patterns.","cover_image":null,"user_id":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234","created_at":"2024-02-01T09:00:00.000Z","updated_at":"2024-02-05T16:30:00.000Z","settings":null}],"pagination":{"page":1,"limit":20,"total":2,"totalPages":1}}}}},"401":{"description":"Authentication required. Provide a valid Bearer token.","content":{"application/json":{"example":{"error":"Unauthorized","code":"UNAUTHORIZED"}}}}}},"post":{"summary":"Create a new course","description":"Creates a new course in the connected space. Personal OAuth creates a personal course owned by the connected user and cannot assign another owner. For a workspace connection, by default it is owned by the token user; optionally provide owner_email (or owner_id) to assign an existing workspace member. Use one selector only. Requires courses:create (or api:*).\n\n### Set the course language and theme\n\n1. Call `GET /themes` with `courses:read` and select a theme ID.\n2. Call `POST /courses` with `courses:create`:\n\n```json\n{\n  \"title\": \"Ma formation\",\n  \"default_locale\": \"fr\",\n  \"theme_id\": \"a1b2c3d4-e5f6-4789-abcd-ef1234567890\",\n  \"theme_config\": { \"colors\": { \"primary\": \"#1d4ed8\" } }\n}\n```\n\nReplace the example UUID with an ID from the list. `default_locale` initializes the course language and built-in learner labels; it does not translate authored content. `theme_config` is optional and applies only to this course.\n\nTo change the theme later, send `theme_id` and/or `theme_config` to `PUT /courses/{courseId}` with `courses:update`. Only supplied fields change. `theme_config` replaces the full override object; use `null` to clear it. Changing `theme_id` alone keeps existing overrides; send `theme_config: null` to use the selected theme without course overrides. An inaccessible theme returns `403 REFERENCE_FORBIDDEN` before the course is written. The same theme fields are supported under `course` in `POST /courses/import`.","operationId":"createCourse","tags":["Courses"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseCreate"},"examples":{"minimal":{"summary":"Minimal course","description":"Create a course with just a title.","value":{"title":"My New Course"}},"assignedOwner":{"summary":"Create a course for a workspace member","value":{"title":"My New Course","owner_email":"jordan@example.com"}},"complete":{"summary":"Complete course","description":"Create a course with all optional fields.","value":{"title":"Introduction to JavaScript","description":"Learn the fundamentals of JavaScript programming.","cover_image":"https://example.com/cover.jpg","settings":{"navigation":{"allow_skip":false}},"default_locale":"fr"}}}}}},"responses":{"201":{"description":"Course created successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Course"}}},"example":{"success":true,"data":{"id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Introduction to JavaScript","description":"Learn the fundamentals of JavaScript programming.","cover_image":null,"user_id":"usr_e5f6a7b8-c9d0-1234-ef12-345678901234","created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-15T10:30:00.000Z","settings":{"navigation":{"allow_skip":false}},"default_locale":{"language_code":"fr","language_name":"French","native_name":"Français","is_default":true,"text_direction":"ltr"}}}}}},"400":{"description":"Validation error in request body, or invalid/ambiguous owner selectors (INVALID_COURSE_OWNER). Provide only owner_email or owner_id, matching an existing member of the token workspace.","content":{"application/json":{"example":{"error":"Validation failed","code":"VALIDATION_ERROR","details":{"field":"title","reason":"Title is required"}}}}},"401":{"description":"Unauthorized"}}}},"/courses/import":{"post":{"summary":"Import full course in one request","description":"Creates a complete course tree (course, optional sections, variants, slides, blocks, and checkpoints) from a single payload. Courses stay personal for personal OAuth, or are attached to the token workspace for workspace connections. Personal access cannot assign another owner. Optional course.owner_email (or course.owner_id) assigns ownership to an existing workspace member; provide one selector only. Otherwise the token user owns the course.","operationId":"importCourse","tags":["Courses"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseImportRequest"}}}},"responses":{"201":{"description":"Course imported successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseImportResponse"},"example":{"success":true,"data":{"course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","sections_created":1,"variants_created":1,"slides_created":1,"blocks_created":2,"checkpoints_created":1}}}}},"400":{"description":"Validation error in payload.","content":{"application/json":{"example":{"error":"Validation error","details":[{"path":["slides",0,"section_key"],"message":"Invalid section reference"}]}}}},"403":{"description":"Insufficient scopes or quota exceeded.","content":{"application/json":{"example":{"error":"Insufficient permissions. Missing scopes: sections:create, slides:create, blocks:create","code":"FORBIDDEN"}}}}}}},"/courses/{courseId}":{"get":{"summary":"Retrieve a course","description":"Retrieves details of a specific course by ID.","operationId":"getCourse","tags":["Courses"],"parameters":[{"name":"courseId","in":"path","required":true,"description":"Unique identifier of the course.","schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Course retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Course"}}}}}},"404":{"description":"Course not found.","content":{"application/json":{"example":{"error":"Course not found","code":"RESOURCE_NOT_FOUND"}}}}}},"put":{"summary":"Update a course","description":"Updates an existing course in the connected personal or workspace space. Personal OAuth cannot update a workspace course or transfer ownership. Only supplied fields change. Set owner_email (or owner_id) to assign an existing workspace member as owner; use one selector only. Ownership and supplied metadata update atomically. The former owner remains an editor and the new owner becomes course admin. Requires courses:update (or api:*).","operationId":"updateCourse","tags":["Courses"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseUpdate"},"example":{"title":"Updated Course Title","description":"Updated description for the course.","owner_email":"jordan@example.com"}}}},"responses":{"200":{"description":"Course updated successfully.","content":{"application/json":{"example":{"success":true,"data":{"id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Updated Course Title","description":"Updated description for the course.","updated_at":"2024-01-25T10:00:00.000Z"}}}}},"400":{"description":"Invalid request body or owner selectors (INVALID_COURSE_OWNER). Provide only owner_email or owner_id, matching an existing member of the token workspace."},"403":{"description":"Token is missing courses:update permission."},"404":{"description":"Course not found in the token workspace"}}},"delete":{"summary":"Delete a course","description":"Permanently deletes a course and all its contents (sections, slides, blocks). There is no undo. Through MCP, the user must approve the exact request in the in-chat confirmation card or the ScormStack approval page before it can execute.","operationId":"deleteCourse","tags":["Courses"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Course deleted successfully.","content":{"application/json":{"example":{"success":true,"message":"Course deleted"}}}},"404":{"description":"Course not found"}}}},"/courses/{courseId}/analytics/learners":{"get":{"summary":"List course learners and analytics","description":"Returns the same learner rows and summary metrics shown in Courses Analytics → Learners. Search applies to learner ID, email, name, and nickname.","operationId":"listCourseLearnerAnalytics","tags":["Analytics"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string","maxLength":500}},{"name":"sortBy","in":"query","schema":{"type":"string","default":"updated_at","enum":["learner_id","learner_email","learner_name","learner_pseudo","score","progress","completion_status","success_status","lesson_status","session_time","created_at","updated_at"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"includeFullData","in":"query","description":"Include each learner's raw suspend_data field.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Learner analytics retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/LearnerAnalytics"}},"summary":{"$ref":"#/components/schemas/LearnerAnalyticsSummary"},"pagination":{"$ref":"#/components/schemas/Pagination"},"sorting":{"type":"object","properties":{"sortBy":{"type":"string"},"sortOrder":{"type":"string","enum":["asc","desc"]}}},"filters":{"type":"object","properties":{"search":{"type":"string"},"includeFullData":{"type":"boolean"}}}},"required":["success","data","summary","pagination","sorting","filters"]}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Invalid or missing Personal Access Token"},"403":{"description":"Token is missing the analytics:read scope"},"404":{"description":"Course not found in the token workspace"},"429":{"description":"Rate limit exceeded"}}},"delete":{"summary":"Delete learner analytics","description":"Permanently deletes up to 1,000 selected learners and their course sessions and interactions. There is no undo. Through MCP, the user must approve the exact course and learner IDs in the in-chat confirmation card or the ScormStack approval page before it can execute.","operationId":"deleteCourseLearnerAnalytics","tags":["Analytics"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearnerAnalyticsDeleteRequest"}}}},"responses":{"200":{"description":"Learner analytics deleted successfully.","content":{"application/json":{"example":{"success":true,"data":{"learner_ids":["learner-1042","learner-1043"]}}}}},"400":{"description":"Invalid or missing JSON request body"},"401":{"description":"Invalid or missing Personal Access Token"},"403":{"description":"Token is missing the analytics:delete scope"},"404":{"description":"Course or learner not found"},"429":{"description":"Rate limit exceeded"}}}},"/courses/{courseId}/full":{"get":{"summary":"Get full course structure","description":"Retrieves an import-compatible full course payload including course settings, default locale, sections, variants, slides, blocks, and checkpoints. The response `data` object can be edited externally and posted to `POST /courses/import` to create a new copy.","operationId":"getFullCourse","tags":["Courses"],"parameters":[{"name":"courseId","in":"path","required":true,"description":"Unique identifier of the course.","schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Full course payload retrieved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseFullExportResponse"},"example":{"success":true,"data":{"course":{"title":"Onboarding Essentials","description":"Get learners operational in less than 10 minutes.","settings":{"navigation":{"allow_skip":false}},"status":"draft"},"sections":[{"key":"section_core","source_id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","title":"Core Concepts","order_index":0}],"variants":[{"key":"variant_fast_track","label":"Fast Track","is_required":false,"details":{},"order_index":0}],"slides":[{"key":"slide_welcome","source_id":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012","title":"Welcome","slide_type":"content","section_key":"section_core","order_index":0,"variant_keys":null,"blocks":[{"key":"block_intro","source_id":"blk_d4e5f6a7-b8c9-0123-def1-234567890123","type":"text","variant":"heading","content":{"heading":"Welcome","paragraph_1":"<p>Start here.</p>"},"position":0}]}],"checkpoints":[]}}}}},"403":{"description":"Missing one of the required read scopes: courses:read, sections:read, slides:read, blocks:read."},"404":{"description":"Course not found."}}}},"/courses/{courseId}/exports":{"get":{"summary":"List published course exports","description":"Lists completed exports created through the app or API, newest creation first (ID breaks ties). Includes saved settings, dates, public links, and dynamic package export_id values usable as target_export_id. Requires courses:read, courses:update, or legacy courses:publish and access to the connected workspace's course. This is the current state of each export, not a revision history: dynamic refresh updates the same record. Pending, failed, and deleted exports are excluded. Multiple records can refer to the same hosted embed ID.","operationId":"listCourseExports","tags":["Publishing"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Completed exports and pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseExportList"}}}},"400":{"description":"Invalid pagination"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient token scope"},"404":{"description":"Course not found or access denied"},"500":{"description":"Failed to retrieve exports"}}}},"/courses/{courseId}/publish":{"post":{"summary":"Publish a course","description":"Starts publication of a course using the same export options exposed in the app.\n\nPackage exports return either a signed download URL immediately or a `request_id` plus `status_url` when background processing is required. When a package is ready, configured workspace webhooks receive a signed `course_published` event.\n\nTo refresh an existing dynamic package, send only `refresh_dynamic_content_only: true`, `target_export_id` (the `export_id` returned by creation or `GET /courses/{courseId}/exports`), and optionally `notify_webhooks: false`. The response is HTTP 200 with the same `export_id` (also returned as `request_id`). Saved export settings and hosted data URLs are preserved; the LMS ZIP does not need to be replaced. No new export slot is consumed. By default, configured webhooks receive `dynamic_course_updated`. Static, incomplete, deleted, and public-link exports cannot use this mode. Use the public-link update mode below for hosted links.\n\nThe `courseId` must belong to the connected space. Personal OAuth only supports owned courses without a workspace.\n\nUse `format: \"public_link\"` to create or update a hosted learner URL. Password protection is off unless explicitly enabled. Through MCP, the user must approve the exact public-link request in the in-chat confirmation card or the ScormStack approval page before it can execute. The `email` and `linkedin` share options only record the preferred sharing mode; this tool does not send email or post to LinkedIn.","operationId":"publishCourse","x-mcp-open-world":true,"tags":["Publishing"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoursePublishRequest"},"examples":{"dynamicScorm":{"summary":"Create a dynamic SCORM package","value":{"format":"scorm","version":"2004","dynamic_content":true}},"refreshDynamic":{"summary":"Update an existing dynamic package without replacing the LMS ZIP","value":{"refresh_dynamic_content_only":true,"target_export_id":"11111111-1111-4111-8111-111111111111","notify_webhooks":false}},"scormAsync":{"summary":"SCORM package with bundled assets","value":{"format":"scorm","version":"2004","include_assets":true,"locale":"fr","track_progress":true,"learner_identification_type":"email"}},"publicLink":{"summary":"Public hosted link","value":{"format":"public_link","publish_mode":"new","share_option":"link","locale":"en"}},"xapi":{"summary":"xAPI package","value":{"format":"xapi","include_assets":true}},"cmi5":{"summary":"cmi5 package","value":{"format":"cmi5","include_assets":true}}}}}},"responses":{"200":{"description":"Publication completed synchronously.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoursePublishResponse"}}}},"202":{"description":"Publication started in the background.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoursePublishResponse"},"example":{"success":true,"data":{"request_id":"req_1234567890abcdef","status":"pending","format":"scorm","version":"2004","status_url":"/api/v1/courses/crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890/publish/req_1234567890abcdef","asset_count":12,"estimated_size_formatted":"48.2 MB","webhook_delivery":"course_published will be sent when the package is ready"}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or plan limit"},"404":{"description":"Course not found"}}}},"/courses/{courseId}/publish/{requestId}":{"get":{"summary":"Retrieve publish status","description":"Retrieves the status, saved settings, dates, and result URL for a publication request. The requestId path parameter accepts the export_id returned by creation or the exports list.","operationId":"getPublishStatus","tags":["Publishing"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"requestId","in":"path","required":true,"schema":{"type":"string"},"example":"req_1234567890abcdef"}],"responses":{"200":{"description":"Publish request status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoursePublishStatus"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Course or publish request not found"}}}},"/courses/{courseId}/sections":{"get":{"summary":"List course sections","description":"Retrieves all sections in a course, ordered by their position.","operationId":"listSections","tags":["Sections"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Sections retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Section"}}}},"example":{"success":true,"data":[{"id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Getting Started","description":"Set up your development environment.","icon":"rocket","order_index":0,"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"},{"id":"sec_c3d4e5f6-a7b8-9012-cdef-234567890123","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Core Concepts","description":"Learn the fundamental concepts.","icon":"book","order_index":1,"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"}]}}}}}},"post":{"summary":"Create a section","description":"Creates a new section in the course.","operationId":"createSection","tags":["Sections"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionCreate"},"example":{"title":"Getting Started","description":"Set up your development environment.","icon":"rocket"}}}},"responses":{"201":{"description":"Section created successfully.","content":{"application/json":{"example":{"success":true,"data":{"id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Getting Started","description":"Set up your development environment.","icon":"rocket","order_index":0,"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-15T10:30:00.000Z"}}}}}}}},"/courses/{courseId}/sections/{sectionId}":{"get":{"summary":"Retrieve a section","description":"Retrieves details of a specific section.","operationId":"getSection","tags":["Sections"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"sectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"}],"responses":{"200":{"description":"Section retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Section"}}}}}},"404":{"description":"Section not found"}}},"put":{"summary":"Update a section","description":"Updates an existing section.","operationId":"updateSection","tags":["Sections"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"sectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SectionCreate"},"example":{"title":"Updated Section Title"}}}},"responses":{"200":{"description":"Section updated"}}},"delete":{"summary":"Delete a section","description":"Deletes a section. Slides in this section will be moved out of the section.","operationId":"deleteSection","tags":["Sections"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"sectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"}],"responses":{"200":{"description":"Section deleted"}}}},"/courses/{courseId}/slides":{"get":{"summary":"List course slides","description":"Retrieves all slides in a course, optionally filtered by section.","operationId":"listSlides","tags":["Slides"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"section_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filter slides by section ID.","example":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"}],"responses":{"200":{"description":"Slides retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Slide"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"example":{"data":[{"id":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","section_id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","title":"Variables and Data Types","order_index":0,"content":{"optional":false,"show_in_toc":true,"hide_in_navigation":false},"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"},{"id":"sld_d4e5f6a7-b8c9-0123-def1-345678901234","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","section_id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901","title":"Functions and Scope","order_index":1,"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"}],"pagination":{"page":1,"limit":20,"total":2,"totalPages":1}}}}}}},"post":{"summary":"Create a slide","description":"Creates a new slide in the course. Set content.optional, content.show_in_toc (Show on homepage), and content.hide_in_navigation as booleans. Missing flags default to false, true, and false respectively.","operationId":"createSlide","tags":["Slides"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlideCreate"},"examples":{"inSection":{"summary":"Slide in a section","value":{"title":"Variables and Data Types","section_id":"sec_b2c3d4e5-f6a7-8901-bcde-f12345678901"}},"standalone":{"summary":"Standalone slide","value":{"title":"Introduction"}},"optionalResource":{"summary":"Optional resource reached by a direct slide link","value":{"title":"Extra resources","content":{"optional":true,"show_in_toc":false,"hide_in_navigation":true}}}}}}},"responses":{"201":{"description":"Slide created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Slide"}},"required":["success","data"]}}}}}}},"/courses/{courseId}/slides/{slideId}":{"get":{"summary":"Retrieve a slide","description":"Retrieves details of a specific slide.","operationId":"getSlide","tags":["Slides"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"}],"responses":{"200":{"description":"Slide details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Slide"}},"required":["success","data"]}}}},"404":{"description":"Slide not found"}}},"put":{"summary":"Update a slide","description":"Updates an existing slide. Pass property changes under content; only supplied flags are merged, preserving omitted flags and other content settings. The flags remain saved but are ignored while the slide has variant assignments; variant rules control visibility and completion.","operationId":"updateSlide","tags":["Slides"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlideUpdate"},"example":{"content":{"optional":true}}}}},"responses":{"200":{"description":"Slide updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Slide"}},"required":["success","data"]}}}}}},"delete":{"summary":"Delete a slide","description":"Permanently deletes a slide and all its blocks.","operationId":"deleteSlide","tags":["Slides"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"}],"responses":{"200":{"description":"Slide deleted"}}}},"/courses/{courseId}/slides/{slideId}/blocks":{"get":{"summary":"List slide blocks","description":"Retrieves all blocks on a slide, in display order.","operationId":"listBlocks","tags":["Blocks"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"}],"responses":{"200":{"description":"Blocks retrieved successfully.","content":{"application/json":{"example":{"success":true,"data":[{"id":"blk_d4e5f6a7-b8c9-0123-def1-234567890123","type":"text","variant":"heading","content":{"heading":"Variables and Data Types","paragraph_1":"<p>In this lesson, you'll learn about JavaScript variables.</p>"},"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"},{"id":"blk_e5f6a7b8-c9d0-1234-ef12-456789012345","type":"flashcards","variant":"stack","content":{"cards":[{"id":"c1","front":{"content":"<p>What is let?</p>"},"back":{"content":"<p>A block-scoped variable declaration.</p>"}}]},"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-20T14:45:00.000Z"}]}}}}}},"post":{"summary":"Create a block","description":"Creates a new content block and adds it to the slide.\n\nThe `content` structure varies by block type. See the examples below or use `GET /blocks/defaults` to get templates for each block type.","operationId":"createBlock","tags":["Blocks"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockCreate"},"examples":{"textHeading":{"summary":"Text block (heading variant)","description":"Creates a text block with a large heading and paragraph content.","value":{"type":"text","variant":"heading","content":{"heading":"Welcome to JavaScript","paragraph_1":"<p>JavaScript is a versatile programming language that powers the modern web.</p>","options":{"headingSize":"large","headingFormat":"simple"}}}},"textParagraph":{"summary":"Text block (paragraph variant)","description":"Creates a text block focused on paragraph content.","value":{"type":"text","variant":"paragraph","content":{"heading":"","paragraph_1":"<p>This is a paragraph of text content. You can use <strong>bold</strong>, <em>italic</em>, and other HTML formatting.</p>"}}},"image":{"summary":"Image block","description":"Creates an image block with caption and styling options.","value":{"type":"image","variant":"image","content":{"text":"<p>A diagram showing the JavaScript event loop</p>","images":{"image_1":{"src":"https://example.com/images/event-loop.png","alt":"JavaScript event loop diagram","caption":"The JavaScript event loop processes tasks from the queue","position":"center"}},"options":{"box_shadow":true,"show_caption":true,"rounded_corners":true}}}},"video":{"summary":"Video block (YouTube)","description":"Creates a video block embedding a YouTube video.","value":{"type":"video","variant":"youtube","content":{"url":"https://www.youtube.com/watch?v=W6NZfCO5SIk","provider":"youtube","autoplay":false,"controls":true,"loop":false,"muted":false}}},"flashcards":{"summary":"Flashcards block","description":"Creates an interactive flashcard deck for memorization.","value":{"type":"flashcards","variant":"stack","content":{"cards":[{"id":"card-1","front":{"content":"<p>What is a variable in JavaScript?</p>"},"back":{"content":"<p>A variable is a container for storing data values. You declare variables using <code>let</code>, <code>const</code>, or <code>var</code>.</p>"}},{"id":"card-2","front":{"content":"<p>What is the difference between <code>let</code> and <code>const</code>?</p>"},"back":{"content":"<p><code>let</code> allows reassignment, while <code>const</code> creates a read-only reference that cannot be reassigned.</p>"}},{"id":"card-3","front":{"content":"<p>What are the primitive data types in JavaScript?</p>"},"back":{"content":"<p>String, Number, BigInt, Boolean, Undefined, Null, and Symbol.</p>"}}],"settings":{"showProgress":true,"flipDirection":"horizontal","shuffleCards":false}}}},"accordion":{"summary":"Accordion block","description":"Creates collapsible content sections.","value":{"type":"accordion","variant":"accordion_with_icon","content":{"items":[{"id":"item-1","title":"What is JavaScript?","content":"<p>JavaScript is a high-level, interpreted programming language that conforms to the ECMAScript specification.</p>","icon":"code"},{"id":"item-2","title":"Where can JavaScript run?","content":"<p>JavaScript runs in web browsers, on servers (Node.js), in mobile apps (React Native), and even on desktop applications (Electron).</p>","icon":"globe"},{"id":"item-3","title":"Is JavaScript the same as Java?","content":"<p>No! Despite the similar name, JavaScript and Java are completely different languages with different syntax and use cases.</p>","icon":"help-circle"}],"options":{"type":"single","defaultOpen":"item-1"}}}},"tabs":{"summary":"Tabs block","description":"Creates tabbed content panels.","value":{"type":"tabs","variant":"tabs_with_icon","content":{"items":[{"id":"tab-1","title":"Variables","content":"<p>Use <code>let</code> for values that change, <code>const</code> for constants.</p>"},{"id":"tab-2","title":"Functions","content":"<p>Functions are reusable blocks of code: <code>function greet(name) { return 'Hello ' + name; }</code></p>"},{"id":"tab-3","title":"Arrays","content":"<p>Arrays store multiple values: <code>const fruits = ['apple', 'banana', 'orange'];</code></p>"}],"options":{"type":"horizontal","defaultTab":"tab-1"}}}},"fillInBlank":{"summary":"Fill-in-the-blank assessment","description":"Creates a fill-in-the-blank quiz question.","value":{"type":"fill_in_blank","variant":"default","content":{"text":"<p>In JavaScript, you use the {{blank_1}} keyword to declare a variable that cannot be reassigned, and the {{blank_2}} keyword for variables that can change.</p>","blanks":[{"id":"blank_1","correctAnswers":["const"],"caseSensitive":false},{"id":"blank_2","correctAnswers":["let","var"],"caseSensitive":false}],"settings":{"showCorrectAnswers":true,"allowRetry":true},"grading":{"enabled":true,"points":10,"partialCredit":true}}}},"matching":{"summary":"Matching assessment","description":"Creates a drag-and-drop matching exercise.","value":{"type":"matching","variant":"default","content":{"instructions":"<p>Match each JavaScript concept with its description.</p>","pairs":[{"id":"pair-1","left":{"id":"l1","content":"<p><code>let</code></p>"},"right":{"id":"r1","content":"<p>Block-scoped, reassignable variable</p>"}},{"id":"pair-2","left":{"id":"l2","content":"<p><code>const</code></p>"},"right":{"id":"r2","content":"<p>Block-scoped, non-reassignable variable</p>"}},{"id":"pair-3","left":{"id":"l3","content":"<p><code>var</code></p>"},"right":{"id":"r3","content":"<p>Function-scoped, reassignable variable</p>"}}],"settings":{"shuffleItems":true,"showFeedback":true},"grading":{"enabled":true,"points":15}}}},"callout":{"summary":"Callout block","description":"Creates a highlighted info/tip/warning box.","value":{"type":"callout","variant":"tip","content":{"type":"tip","title":"Pro Tip","content":"<p>Always use <code>const</code> by default, and only use <code>let</code> when you know the variable needs to be reassigned.</p>"}}},"list":{"summary":"List block","description":"Creates a bulleted, numbered, or icon list.","value":{"type":"list","variant":"bullet","content":{"items":[{"id":"item-1","content":"<p>Variables store data values</p>","icon":"check"},{"id":"item-2","content":"<p>Functions are reusable code blocks</p>","icon":"check"},{"id":"item-3","content":"<p>Arrays hold multiple values</p>","icon":"check"},{"id":"item-4","content":"<p>Objects store key-value pairs</p>","icon":"check"}],"options":{"listType":"bullet","showIcons":false}}}},"resources":{"summary":"Resources block","description":"Creates a downloadable resources list.","value":{"type":"resources","variant":"list","content":{"title":"Additional Resources","items":[{"id":"res-1","title":"JavaScript MDN Documentation","description":"Comprehensive JavaScript reference","type":"link","url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript"},{"id":"res-2","title":"Course Cheat Sheet","description":"PDF summary of all concepts covered","type":"file","fileUrl":"https://example.com/files/js-cheatsheet.pdf","fileName":"javascript-cheatsheet.pdf"}]}}},"flow":{"summary":"Flow block (step-by-step)","description":"Creates a guided step-by-step experience with images.","value":{"type":"flow","variant":"default","content":{"intro":{"content":"<p>Let's walk through creating your first JavaScript variable.</p>","startButtonText":"Start Tutorial"},"steps":[{"title":"Step 1: Open your editor","content":"<p>Open your code editor (VS Code, Sublime, etc.) and create a new file called <code>script.js</code>.</p>","media":{"url":"https://example.com/images/step1-editor.png","type":"image","position":"center"}},{"title":"Step 2: Declare a variable","content":"<p>Type <code>const greeting = 'Hello, World!';</code> in your file.</p>","media":{"url":"https://example.com/images/step2-variable.png","type":"image","position":"center"}},{"title":"Step 3: Log the value","content":"<p>Add <code>console.log(greeting);</code> on the next line to output the value.</p>"}],"outro":{"content":"<p>Congratulations! You've created your first JavaScript variable.</p>","completionMessage":"Tutorial completed!"},"settings":{"showProgress":true,"allowSkip":false}}}},"timeline":{"summary":"Timeline block","description":"Creates an interactive timeline with dated events and expandable rich details.","value":{"type":"timeline","variant":"default","content":{"events":[{"id":"event-1","date":"1995","name":"JavaScript is created","description":"Brendan Eich creates the first version of JavaScript.","icon":"light-bulb","image":{"src":"https://example.com/images/javascript-1995.png","alt":"Early web browser interface","caption":"JavaScript began as a browser scripting language.","position":"center"},"content":"<p>JavaScript was created to make web pages dynamic and interactive inside the browser.</p>"},{"id":"event-2","date":"2009","name":"Node.js expands JavaScript","description":"JavaScript starts running outside the browser.","icon":"server","image":null,"content":"<p>Node.js made JavaScript useful for server-side applications, build tools, and automation.</p>"}],"settings":{"layout":"vertical","displayMode":"expandable","completionMode":"tried","showConnectors":true,"connectorColor":"auto"}}}},"categorization":{"summary":"Categorization assessment","description":"Creates a drag-and-drop sorting exercise.","value":{"type":"categorization","variant":"checklist","content":{"instructions":"<p>Sort these items into the correct JavaScript data type category.</p>","categories":[{"id":"cat-1","title":"Primitive Types","color":"#4CAF50"},{"id":"cat-2","title":"Reference Types","color":"#2196F3"}],"items":[{"id":"item-1","content":"<p><code>\"hello\"</code></p>","correctCategory":"cat-1"},{"id":"item-2","content":"<p><code>42</code></p>","correctCategory":"cat-1"},{"id":"item-3","content":"<p><code>true</code></p>","correctCategory":"cat-1"},{"id":"item-4","content":"<p><code>{ name: 'John' }</code></p>","correctCategory":"cat-2"},{"id":"item-5","content":"<p><code>[1, 2, 3]</code></p>","correctCategory":"cat-2"}],"settings":{"shuffleItems":true,"showFeedback":true},"grading":{"enabled":true,"points":20,"partialCredit":true}}}},"sorting":{"summary":"Sorting assessment","description":"Creates an ordering exercise with drag-and-drop and accessible position inputs.","value":{"type":"sorting","variant":"default","content":{"title":"Order the JavaScript workflow","instructions":"Put the steps in the correct order.","items":[{"id":"item-1","type":"text","textContent":"<p>Create the file</p>"},{"id":"item-2","type":"text","textContent":"<p>Write the code</p>"},{"id":"item-3","type":"text","textContent":"<p>Run the script</p>"}],"correctOrder":["item-1","item-2","item-3"],"settings":{"shuffleItems":true,"showPositionInputs":true,"showMoveButtons":true,"direction":"vertical"},"grading":{"partialCredit":true,"weight":1}}}},"openResponse":{"summary":"Open response assessment","description":"Creates a free-text response question.","value":{"type":"open_response","variant":"default","content":{"question":"<p>Explain in your own words what a JavaScript function is and why functions are useful.</p>","placeholder":"Type your answer here...","minLength":50,"maxLength":500,"rubric":"<p>A good answer should mention: reusable code, parameters, return values, and code organization.</p>"}}},"reactions":{"summary":"Reactions block","description":"Captures a single learner reaction, with optional follow-up comment for outdated content or questions.","value":{"type":"reactions","variant":"default","content":{"settings":{"completionMode":"viewed","enablementCondition":"previous_block"}}}},"embed":{"summary":"Embed block","description":"Embeds external content via iframe.","value":{"type":"embed","variant":"iframe","content":{"url":"https://codepen.io/embed/preview/abcdef","title":"Interactive Code Example","height":400}}},"separator":{"summary":"Separator block","description":"Creates a visual divider between content sections.","value":{"type":"separator","variant":"line","content":{"style":"line","spacing":"medium"}}}}}}},"responses":{"201":{"description":"Block created and added to slide.","content":{"application/json":{"example":{"success":true,"data":{"id":"blk_d4e5f6a7-b8c9-0123-def1-234567890123","type":"text","variant":"heading","content":{"heading":"Welcome to JavaScript","paragraph_1":"<p>JavaScript is a versatile programming language.</p>"},"created_at":"2024-01-15T10:30:00.000Z","updated_at":"2024-01-15T10:30:00.000Z"}}}}},"400":{"description":"Invalid block content for the specified type.","content":{"application/json":{"example":{"error":"Invalid content for block type 'flashcards'","code":"INVALID_BLOCK_CONTENT","details":{"field":"content.cards","reason":"Cards array is required"}}}}}}}},"/courses/{courseId}/slides/{slideId}/blocks/{blockId}":{"get":{"summary":"Retrieve a block","description":"Retrieves details of a specific block.","operationId":"getBlock","tags":["Blocks"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"},{"name":"blockId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"blk_d4e5f6a7-b8c9-0123-def1-234567890123"}],"responses":{"200":{"description":"Block details"},"404":{"description":"Block not found"}}},"put":{"summary":"Update a block","description":"Updates an existing block's content and/or variant in place, preserving its ID and comments. A variant-only update preserves all stored content. Supported variants are listed by /blocks/defaults.","operationId":"updateBlock","tags":["Blocks"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"},{"name":"blockId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"blk_d4e5f6a7-b8c9-0123-def1-234567890123"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockUpdate"},"example":{"content":{"heading":"Updated Heading","paragraph_1":"<p>Updated paragraph content.</p>"}}}}},"responses":{"200":{"description":"Block updated"},"400":{"description":"Invalid body or unsupported variant (INVALID_BLOCK_VARIANT)."}}},"delete":{"summary":"Remove a block","description":"Removes a block from the slide.","operationId":"deleteBlock","tags":["Blocks"],"parameters":[{"name":"courseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"slideId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"sld_c3d4e5f6-a7b8-9012-cdef-123456789012"},{"name":"blockId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"blk_d4e5f6a7-b8c9-0123-def1-234567890123"}],"responses":{"200":{"description":"Block removed from slide"}}}},"/blocks/defaults":{"get":{"summary":"Get block defaults","description":"Retrieves default content templates for all block types.\n\nUse this endpoint to discover available block types and their content structures. Returns real examples you can copy and modify when creating blocks.","operationId":"getBlockDefaults","tags":["Block Templates"],"parameters":[{"name":"type","in":"query","schema":{"type":"string"},"description":"Filter by block type (e.g., 'text', 'flashcards').","example":"text"},{"name":"variant","in":"query","schema":{"type":"string"},"description":"Get a specific variant. Requires 'type' parameter.","example":"heading"}],"responses":{"200":{"description":"Block defaults retrieved.","content":{"application/json":{"examples":{"allDefaults":{"summary":"All block types","description":"Returns all available block types and their variants.","value":{"success":true,"availableTypes":["slide_intro","separator","text","image","audio","video","embed","pdf","callout","list","table","accordion","tabs","flashcards","timeline","flow","interactive_image","web_simulation","scene","resources","assessment","fill_in_blank","matching","click_on_image","drag_and_drop","success_meter","categorization","sorting","open_response","navigation_button","reactions","time_requirements"],"data":{"text":{"defaultVariant":"heading","createPayload":{"type":"text","variant":"heading","content":{"heading":"Your heading","paragraph_1":"<p>Content here</p>"}},"variants":{"heading":{"variant":"heading","name":"Heading","content":{"heading":"Your heading","paragraph_1":"<p>Content here</p>"},"createPayload":{"type":"text","variant":"heading","content":{"heading":"Your heading","paragraph_1":"<p>Content here</p>"}}},"paragraph":{"variant":"paragraph","name":"Paragraph","content":{"heading":"","paragraph_1":"<p>Your text here</p>"},"createPayload":{"type":"text","variant":"paragraph","content":{"heading":"","paragraph_1":"<p>Your text here</p>"}}}}}}}},"singleType":{"summary":"Single type (?type=flashcards)","value":{"success":true,"data":{"type":"flashcards","defaultVariant":"stack","createPayload":{"type":"flashcards","variant":"stack","content":{"cards":[{"id":"card-1","front":{"content":"<p>Question</p>"},"back":{"content":"<p>Answer</p>"}}]}},"variants":{"stack":{"variant":"stack","name":"Stack","content":{"cards":[{"id":"card-1","front":{"content":"<p>Question</p>"},"back":{"content":"<p>Answer</p>"}}]},"createPayload":{"type":"flashcards","variant":"stack","content":{"cards":[{"id":"card-1","front":{"content":"<p>Question</p>"},"back":{"content":"<p>Answer</p>"}}]}}}}}}}}}}},"404":{"description":"Block type or variant not found"}}}},"/assets":{"get":{"summary":"List assets","description":"Retrieves a paginated list of accessible assets (images, videos, audio, PDFs). Returns metadata and URLs, not image pixels. Use getAssetPreview with an image asset ID for visual inspection before writing alt text.","operationId":"listAssets","tags":["Assets"],"parameters":[{"name":"page","in":"query","description":"Page number for pagination (1-indexed).","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","description":"Number of items per page (max 100).","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}},{"name":"type","in":"query","description":"Filter by asset type.","schema":{"type":"string","enum":["image","video","audio","pdf"]}},{"name":"course_id","in":"query","description":"Filter assets by course ID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Assets retrieved successfully.","content":{"application/json":{"example":{"success":true,"data":[{"id":"ast_a1b2c3d4-e5f6-7890-abcd-ef1234567890","file_name":"course-banner_1704067200.jpg","file_type":"image/jpeg","file_size":245760,"url":"https://cdn.scormstack.com/medias/courses/123/course-banner_1704067200.jpg","width":1920,"height":1080,"created_at":"2024-01-01T10:00:00.000Z"},{"id":"ast_b2c3d4e5-f6a7-8901-bcde-f12345678901","file_name":"intro-video_1704067300.mp4","file_type":"video/mp4","file_size":52428800,"url":"https://cdn.scormstack.com/medias/courses/123/intro-video_1704067300.mp4","width":1280,"height":720,"metadata":{"duration":120},"created_at":"2024-01-01T10:05:00.000Z"}],"pagination":{"page":1,"limit":20,"total":2,"totalPages":1}}}}},"401":{"description":"Unauthorized"}}},"post":{"summary":"Upload a small asset (legacy)","description":"Upload a small asset file through the API function.\n\nThis legacy multipart endpoint is suitable only when the complete request is below the hosting platform's 4.5MB payload limit. For videos and other large files, use the three-step direct upload flow:\n\n1. `POST /assets/uploads` to obtain a pre-signed URL\n2. `PUT` the file directly to that URL\n3. `POST /assets/uploads/complete` to register the asset\n\n**Supported file types:**\n- **Images:** JPEG, PNG, GIF, WebP, SVG (max 10MB)\n- **Videos:** MP4, WebM, MOV, AVI (max 100MB; 250MB with Pro; 250MB with Enterprise)\n- **Audio:** MP3, WAV, OGG, FLAC, M4A (max 100MB)\n- **PDF:** PDF documents (max 50MB)\n\n**Usage:** Send a multipart/form-data request with:\n- `file` (required): The file to upload\n- `course_id` (required): The course to associate the asset with","operationId":"uploadAsset","tags":["Assets"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The file to upload."},"course_id":{"type":"string","format":"uuid","description":"The course ID to associate the asset with."}},"required":["file","course_id"]}}}},"responses":{"201":{"description":"Asset uploaded successfully.","content":{"application/json":{"example":{"success":true,"data":{"id":"ast_a1b2c3d4-e5f6-7890-abcd-ef1234567890","file_name":"lesson-image_1704067200.jpg","file_type":"image/jpeg","file_size":245760,"category":"image","url":"https://cdn.scormstack.com/medias/courses/123/lesson-image_1704067200.jpg","created_at":"2024-01-01T10:00:00.000Z"}}}}},"400":{"description":"Invalid file or validation error.","content":{"application/json":{"examples":{"missingFile":{"summary":"No file provided","value":{"error":"No file provided. Send a file in the 'file' field.","code":"MISSING_FILE"}},"missingCourseId":{"summary":"No course_id provided","value":{"error":"course_id is required.","code":"MISSING_COURSE_ID"}},"invalidType":{"summary":"Unsupported file type","value":{"error":"Unsupported file type: text/plain. Allowed types: images, videos, audio, pdf.","code":"INVALID_FILE_TYPE"}},"tooLarge":{"summary":"File too large","value":{"error":"File too large. Maximum size for image: 10MB. Your file: 15MB.","code":"FILE_TOO_LARGE"}}}}}},"401":{"description":"Unauthorized"}}}},"/assets/uploads":{"post":{"summary":"Create a direct asset upload","description":"Create a short-lived pre-signed URL for uploading an asset directly to storage without sending the file through the ScormStack API function.\n\nThe user’s application or an HTTP-capable upload client must send the exact file bytes to `data.upload_url` with an HTTP `PUT`, including every header returned in `data.headers`. This MCP connector cannot upload the bytes itself. Only after that upload succeeds, call `completeAssetUpload` with the returned `key` and the same `course_id`. Do not call completion or claim the asset is uploaded just because a URL was created.\n\nThe pre-signed URL expires after five minutes.","operationId":"createAssetUpload","tags":["Assets"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_name":{"type":"string","description":"Original file name, including its extension.","example":"introduction.mp4"},"file_type":{"type":"string","description":"MIME type sent with the direct upload.","example":"video/mp4"},"file_size":{"type":"integer","minimum":1,"description":"File size in bytes.","example":51380224},"course_id":{"type":"string","format":"uuid","description":"Course to associate the asset with."}},"required":["file_name","file_type","file_size","course_id"]}}}},"responses":{"201":{"description":"Direct upload created successfully.","content":{"application/json":{"example":{"success":true,"data":{"upload_url":"https://storage.example.com/bucket/medias/courses/course-id/introduction_123.mp4?X-Amz-Signature=...","method":"PUT","headers":{"Content-Type":"video/mp4","Content-Length":"51380224","Cache-Control":"max-age=31536000"},"key":"medias/courses/course-id/introduction_123.mp4","expires_at":"2026-08-25T10:05:00.000Z","complete_url":"/api/v1/assets/uploads/complete"}}}}},"400":{"description":"Invalid file metadata or file too large."},"401":{"description":"Unauthorized"},"404":{"description":"Course not found or access denied."}}}},"/assets/uploads/complete":{"post":{"summary":"Complete a direct asset upload","description":"After the user’s application or upload client has successfully uploaded the bytes using the URL from `createAssetUpload`, verify the stored object, create or update its asset record, and associate it with the course.\n\nScormStack reads the object's actual MIME type and size from storage before accepting it. This request is safe to retry with the same `key`.","operationId":"completeAssetUpload","tags":["Assets"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Storage key returned by createAssetUpload.","example":"medias/courses/course-id/introduction_123.mp4"},"course_id":{"type":"string","format":"uuid","description":"The same course ID used to create the upload."}},"required":["key","course_id"]}}}},"responses":{"201":{"description":"Asset registered successfully.","content":{"application/json":{"example":{"success":true,"data":{"id":"ast_a1b2c3d4-e5f6-7890-abcd-ef1234567890","file_name":"introduction_123.mp4","file_type":"video/mp4","file_size":51380224,"category":"video","url":"https://cdn.scormstack.com/medias/courses/course-id/introduction_123.mp4","created_at":"2026-08-25T10:01:00.000Z"}}}}},"400":{"description":"Invalid upload key or uploaded object metadata."},"401":{"description":"Unauthorized"},"404":{"description":"Course or uploaded object not found."}}}},"/assets/{assetId}/preview":{"get":{"summary":"View an image asset","description":"Retrieves actual image pixels for visual inspection and alt-text review. Requires assets:read, access to the asset in the token's space, and access to the file's original storage scope. Source courses/libraries must also be readable in the token's space; personal-storage files require their owner. Use listAssets to find the asset ID, then call this tool instead of trying to open its CDN URL. REST returns a JPEG; MCP returns an image content block the assistant can inspect if its client supports images. Reads ScormStack storage directly, with a 25 MiB source and 40 megapixel decode limit. Previews fit within 2048 × 2048 and 2 MiB, with a white background for transparency. Animated images show the first frame. External hotlinked images must be uploaded first. Read the surrounding lesson content before writing alt text; never infer visual details from filenames alone.","operationId":"getAssetPreview","tags":["Assets"],"parameters":[{"name":"assetId","in":"path","required":true,"description":"ID of an accessible image asset returned by listAssets or getAsset.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Resized image preview for visual inspection.","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Missing assets:read permission."},"404":{"description":"Asset or original storage scope is not accessible in this space, or its image file is missing."},"413":{"description":"Source or preview exceeds the size limit."},"415":{"description":"Not an image, unsupported format, or image cannot be decoded within limits."},"422":{"description":"Image is not stored in ScormStack storage."},"502":{"description":"Image storage could not be reached."}}}},"/assets/{assetId}":{"get":{"summary":"Get an asset","description":"Retrieves metadata and the URL of a specific asset by ID. For actual image pixels and visual alt-text review, call getAssetPreview with the same assetId.","operationId":"getAsset","tags":["Assets"],"parameters":[{"name":"assetId","in":"path","required":true,"description":"Unique identifier of the asset.","schema":{"type":"string","format":"uuid"},"example":"ast_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Asset retrieved successfully.","content":{"application/json":{"example":{"success":true,"data":{"id":"ast_a1b2c3d4-e5f6-7890-abcd-ef1234567890","file_name":"course-banner_1704067200.jpg","file_type":"image/jpeg","file_size":245760,"url":"https://cdn.scormstack.com/medias/courses/123/course-banner_1704067200.jpg","width":1920,"height":1080,"created_at":"2024-01-01T10:00:00.000Z"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Asset not found.","content":{"application/json":{"example":{"error":"Asset not found","code":"NOT_FOUND"}}}}}},"delete":{"summary":"Delete an asset","description":"Permanently deletes an asset from storage and database.","operationId":"deleteAsset","tags":["Assets"],"parameters":[{"name":"assetId","in":"path","required":true,"description":"Unique identifier of the asset to delete.","schema":{"type":"string","format":"uuid"},"example":"ast_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Asset deleted successfully.","content":{"application/json":{"example":{"success":true,"message":"Asset deleted successfully"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Asset not found.","content":{"application/json":{"example":{"error":"Asset not found","code":"NOT_FOUND"}}}}}}},"/locales/courses/{courseId}":{"get":{"summary":"List course locales","description":"Retrieves all locales (languages) configured for a course, including translation progress.","operationId":"listCourseLocales","tags":["Locales"],"parameters":[{"name":"courseId","in":"path","required":true,"description":"Unique identifier of the course.","schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"responses":{"200":{"description":"Locales retrieved successfully.","content":{"application/json":{"example":{"success":true,"data":[{"id":"loc_a1b2c3d4-e5f6-7890-abcd-ef1234567890","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","language_code":"en","language_name":"English","native_name":"English","is_default":true,"text_direction":"ltr","created_at":"2024-01-15T10:30:00.000Z"},{"id":"loc_b2c3d4e5-f6a7-8901-bcde-f12345678901","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","language_code":"fr","language_name":"French","native_name":"Français","is_default":false,"text_direction":"ltr","created_at":"2024-01-16T09:00:00.000Z"},{"id":"loc_c3d4e5f6-a7b8-9012-cdef-234567890123","course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","language_code":"ar","language_name":"Arabic","native_name":"العربية","is_default":false,"text_direction":"rtl","created_at":"2024-01-17T11:00:00.000Z"}]}}}},"401":{"description":"Unauthorized"},"404":{"description":"Course not found.","content":{"application/json":{"example":{"error":"Course not found or access denied","code":"NOT_FOUND"}}}}}}},"/locales/courses/{courseId}/export":{"get":{"summary":"Export translations (JSON or XLIFF)","description":"Exports native JSON translation units by default. Each unit contains its stable id, type, source, target, text format and sourceHash. HTML strings retain their tags, attributes and entities; use normal JSON serialization, without extra HTML escaping.\n\n**Query Parameters:**\n- `locale` (required): Target language code (e.g., 'fr', 'de', 'es'); the locale must already exist\n- `type`: 'all' (default), 'system_labels', 'content', or 'general'\n- `format`: 'json' (default), 'xml' for raw XLIFF, or 'xliff-json' for the legacy XLIFF-in-JSON envelope\n- `version`: XLIFF version '1.2', '2.0' (default), or '2.1'; ignored for native JSON\n\n**JSON workflow:** Read `data.units`, translate only `target`, then send the `data` object to importTranslations. Preserve id, type, sourceHash, HTML markup, attributes, entities and placeholders. Partial imports are supported. The sourceHash detects a changed or removed source before any import writes.\n\n**Response:** Native JSON returns `{ success, data: { schemaVersion: 1, courseId, locale, units, metadata } }`. XLIFF returns Content-Type application/xliff+xml. The legacy `format=xliff-json` response is `{ success, data: { xliff, filename, metadata } }`.\n\n**Migration:** The default and explicit `format=json` now return native units. Existing XML clients must request `format=xml`; clients expecting `data.xliff` must request `format=xliff-json`.","operationId":"exportTranslations","tags":["Locales"],"parameters":[{"name":"courseId","in":"path","required":true,"description":"Unique identifier of the course.","schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"locale","in":"query","required":true,"description":"Target language code to export translations for.","schema":{"type":"string"},"example":"fr"},{"name":"type","in":"query","description":"Type of content to export.","schema":{"type":"string","enum":["all","system_labels","content","general"],"default":"all"}},{"name":"version","in":"query","description":"XLIFF version for format=xml or xliff-json; ignored for native JSON.","schema":{"type":"string","enum":["1.2","2.0","2.1"],"default":"2.0"}},{"name":"format","in":"query","description":"Native JSON units (default), raw XLIFF XML, or the legacy XLIFF-in-JSON envelope.","schema":{"type":"string","enum":["json","xml","xliff-json"],"default":"json"}}],"responses":{"200":{"description":"Translations exported successfully in the requested format.","content":{"application/json":{"example":{"success":true,"data":{"schemaVersion":1,"locale":"fr","units":[{"id":"course.description","type":"general","format":"html","source":"<p>Read <a href=\"https://example.com\">the guide</a>.</p>","target":"<p>Lisez <a href=\"https://example.com\">le guide</a>.</p>"}]}},"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"oneOf":[{"$ref":"#/components/schemas/TranslationDocument"},{"$ref":"#/components/schemas/XliffJsonExport"}]}}}},"application/xliff+xml":{"schema":{"type":"string"},"example":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n  <file original=\"course_general\" source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\">\n    <body>\n      <trans-unit id=\"course.title\">\n        <source>Introduction to JavaScript</source>\n        <target>Introduction à JavaScript</target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"}}},"400":{"description":"Missing locale or invalid type, version, or format parameter.","content":{"application/json":{"example":{"error":"locale query parameter is required","code":"MISSING_LOCALE"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Course or locale not found"}}}},"/locales/courses/{courseId}/import":{"post":{"summary":"Import translations (JSON or XLIFF)","description":"Imports native JSON translation units (preferred) or XLIFF 1.2, 2.0 and 2.1.\n\n**Request Options:**\n- **JSON:** Send the export's `data` object, or `{ units: [...] }`, with Content-Type application/json. Each unit requires its exported id and type, and a string target to apply. Do not send the outer `{ success, data }` envelope. Optional courseId and locale must match the request. schemaVersion, when supplied, must be 1.\n- **XLIFF:** Send raw XML with Content-Type application/xliff+xml, or a multipart form with a 'file' field.\n\n**MCP:** Call `importTranslations` with a JSON object in `body` by default. A raw XLIFF XML string in `body` remains supported and is sent as XML. Do not JSON-encode either body yourself.\n\nTranslate target values only, preserving HTML tags, attributes, entities and placeholders. Normal JSON serialization handles double quotes, backslashes and newlines; apostrophes need no extra escaping. The API does not HTML-escape or decode JSON strings.\n\nKeep the exported id, type and sourceHash. Non-empty targets with a sourceHash are checked against current source content: a changed or removed source returns 409 TRANSLATION_SOURCE_CHANGED before writes. Re-export and translate the current source. sourceHash is optional for direct updates. Duplicate units and invalid JSON documents return 400. Omitted, empty or whitespace-only targets preserve existing values; an import without any non-empty targets returns NO_TRANSLATIONS.\n\nSystem labels are stored only as overrides of the target language's built-in defaults. Importing a non-empty target equal to its default removes any saved override for that label; an unchanged export therefore keeps inheriting the defaults. Omitted or empty system-label targets preserve existing values. Languages without built-in defaults retain their imported labels.\n\nFor linked library blocks, imports save overrides in this course's locale. They never modify the shared library translation. Course overrides take priority field by field, with library translations as fallback, in the localization panel, translation exports and course exports.\n\n**Import counts:** Each non-empty recognized unit is counted only in its own group (`systemLabels`, `content`, or `general`). `added` means no previous target existed; `modified` means an existing target changed; `unchanged` means it stayed the same. For system labels, existing targets include built-in translations shown by export, with saved overrides taking priority. Section titles are counted individually. `content.skipped` reports units referencing blocks not found in this course; they are not counted as added or modified.\n\n**Query Parameters:**\n- `locale` (required): Target language code (e.g., 'fr', 'de', 'es')\n\nIf the locale doesn't exist, it will be created automatically.","operationId":"importTranslations","tags":["Locales"],"parameters":[{"name":"courseId","in":"path","required":true,"description":"Unique identifier of the course.","schema":{"type":"string","format":"uuid"},"example":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890"},{"name":"locale","in":"query","required":true,"description":"Target language code to import translations for.","schema":{"type":"string"},"example":"fr"}],"requestBody":{"required":true,"description":"Native JSON translation document (preferred), or a raw XLIFF XML string for MCP compatibility.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranslationDocument"},"example":{"schemaVersion":1,"locale":"fr","units":[{"id":"course.description","type":"general","format":"html","source":"<p>Read <a href=\"https://example.com\">the guide</a>.</p>","target":"<p>Lisez <a href=\"https://example.com\">le guide</a>.</p>"}]}},"application/xliff+xml":{"schema":{"type":"string"},"example":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n  <file original=\"course_general\" source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\">\n    <body>\n      <trans-unit id=\"course.title\">\n        <source>Introduction to JavaScript</source>\n        <target>Introduction à JavaScript</target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>"},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The XLIFF file to import."}},"required":["file"]}}}},"responses":{"200":{"description":"Translations imported successfully.","content":{"application/json":{"example":{"success":true,"data":{"imported":{"systemLabels":{"added":5,"modified":2,"unchanged":10},"content":{"added":12,"modified":3,"unchanged":45,"skipped":0},"general":{"added":2,"modified":1,"unchanged":5}},"format":"json","schemaVersion":1,"locale":"fr","localeId":"loc_b2c3d4e5-f6a7-8901-bcde-f12345678901","importedAt":"2024-01-20T14:30:00.000Z"}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"examples":{"missingLocale":{"summary":"Missing locale parameter","value":{"error":"locale query parameter is required","code":"MISSING_LOCALE"}},"invalidJson":{"summary":"Invalid JSON syntax","value":{"error":"Invalid JSON body","code":"INVALID_JSON"}},"invalidTranslations":{"summary":"Invalid JSON translation document or mismatched course/locale","value":{"error":"Each unit requires a valid type and id from the export.","code":"INVALID_TRANSLATIONS"}},"missingFile":{"summary":"Missing XLIFF content","value":{"error":"XLIFF content is required","code":"MISSING_XLIFF"}},"invalidXliff":{"summary":"Invalid XLIFF format","value":{"error":"Invalid XLIFF: Missing xliff root element","code":"INVALID_XLIFF"}},"noTranslations":{"summary":"No translated targets","value":{"error":"No non-empty translations found in the targets","code":"NO_TRANSLATIONS"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Course not found"},"409":{"description":"A JSON sourceHash no longer matches the current source; no translations were written. Re-export before importing.","content":{"application/json":{"example":{"error":"Source changed or was removed; export again before translating: general:course.title","code":"TRANSLATION_SOURCE_CHANGED"}}}}}}},"/webhooks/course_published":{"post":{"x-mcp-expose":false,"summary":"Course published webhook","description":"Outbound webhook delivered when a SCORM, xAPI, or HTML package export has completed.\n\nThis is **not** an API endpoint you call. Configure the destination in **Settings → Workspace → Webhooks** and ScormStack will send events to your server.","operationId":"webhookCoursePublished","tags":["Webhooks"],"parameters":[{"name":"Scormstack-Signature","in":"header","required":true,"description":"HMAC signature of the payload. Format: `t=timestamp,v1=signature` where signature = HMAC_SHA256(secret, `${t}.${rawBody}`)","schema":{"type":"string"},"example":"t=1705327800,v1=0f1d2c3b4a5e6f7890..."},{"name":"Scormstack-Event","in":"header","required":true,"description":"Webhook event type.","schema":{"type":"string"},"example":"course_published"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"evt_1a2b3c4d5e6f7g8h9i0j","object":"event","type":"course_published","created":1705327800,"livemode":false,"data":{"object":{"course_id":"crs_a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Introduction to JavaScript","lms_course_id":"LMS-COURSE-1024","download_url":"https://exports.scormstack.com/exports/req_123/course_scorm2004_with_assets.zip?X-Amz-Signature=...","expiration_date":"2024-01-22T14:45:00.000Z","export_type":"scorm","request_id":"req_1234567890abcdef"}}}}}},"responses":{"200":{"description":"Your endpoint should return a 2xx response to acknowledge receipt."}}}}},"tags":[{"name":"Courses","description":"Manage learning courses.\n\nCourses are the top-level container for all learning content. Each course can contain multiple sections and slides."},{"name":"Themes","description":"Discover accessible themes and apply them using theme_id and optional theme_config on course creation or update. Requires courses:read to list themes."},{"name":"Sections","description":"Organize course content into sections.\n\nSections are optional organizational units that group related slides together. They appear in the course navigation sidebar."},{"name":"Slides","description":"Manage content pages within courses.\n\nSlides are the main content containers. Each slide contains one or more blocks that make up the actual learning content."},{"name":"Blocks","description":"Create and manage content blocks.\n\nBlocks are the building blocks of slides. Each block has a `type` that determines its content structure:\n\n**Content Blocks:**\n- `text` - Rich text with headings and paragraphs\n- `image` - Images with captions\n- `video` - YouTube, Vimeo, or uploaded videos\n- `audio` - Audio with visualizations\n\n**Interactive Blocks:**\n- `flashcards` - Flip card decks\n- `accordion` / `tabs` - Collapsible or tabbed content\n- `flow` - Step-by-step guided experiences\n- `timeline` - Chronological events with expandable details\n\n**Assessment Blocks:**\n- `fill_in_blank` - Fill-in-the-blank questions\n- `matching` - Drag-and-drop matching\n- `categorization` - Sort items into categories\n- `sorting` - Sort items into a sequence\n- `success_meter` - Scenario-based assessments\n- `click_on_image` - Click correct areas on images\n- `open_response` - Free-text responses\n- `reactions` - Single-choice learner reactions with optional feedback comment\n\nSee the **Block Templates** endpoint for real examples of each block type."},{"name":"Block Templates","description":"Get default content templates for block types.\n\nUse these endpoints to discover available block types and get example content structures you can copy and modify."},{"name":"Assets","description":"Upload and manage media assets.\n\nAssets are files (images, videos, audio, PDFs) that can be used in course content blocks.\n\n**Supported file types:**\n- **Images:** JPEG, PNG, GIF, WebP, SVG (max 10MB)\n- **Videos:** MP4, WebM, MOV, AVI (max 100MB; 250MB with Pro; 250MB with Enterprise)\n- **Audio:** MP3, WAV, OGG, FLAC, M4A (max 100MB)\n- **PDF:** PDF documents (max 50MB)\n\nFor files larger than 4MB, use the direct upload flow: create an upload with `POST /assets/uploads`, send the file to the returned storage URL, then register it with `POST /assets/uploads/complete`. The legacy `POST /assets` multipart endpoint remains available for small files."},{"name":"Locales","description":"Manage course translations and localization.\n\nExport and import native JSON translation units through the API and MCP. XLIFF remains available for professional translation tools with explicit `format=xml`.\n\n**Workflow:**\n0. Set the source/default language during course creation with `default_locale` (for example `\"fr\"`)\n1. List available locales with `GET /locales/courses/{courseId}`\n2. Export translations with `GET /locales/courses/{courseId}/export?locale=fr`\n3. Translate `data.units[].target`, preserving identifiers, sourceHash, HTML markup and placeholders\n4. POST the `data` object as application/json to `/locales/courses/{courseId}/import?locale=fr`\n\nExisting XML integrations must request `format=xml`; the previous XLIFF-in-JSON envelope is available as `format=xliff-json`.\n\n**Supported XLIFF versions:** 1.2, 2.0 and 2.1\n\n**Translation types:**\n- **System Labels:** UI strings like buttons, navigation, etc.\n- **Content:** Block content (headings, paragraphs, quiz questions, etc.)\n- **General:** Course title, description, section names, slide titles"},{"name":"Publishing","description":"Publish courses as SCORM, xAPI, HTML packages, or hosted public links."},{"name":"Analytics","description":"Read, export, and delete course learner analytics collected by ScormStack progress tracking."},{"name":"Webhooks","description":"Receive outbound events from ScormStack.\n\nConfigure webhook destinations in **Settings → Workspace → Webhooks**. Events are signed using HMAC-SHA256 in the `Scormstack-Signature` header."}]}