Workspace API

Courses & quizzes

Courses & quizzes endpoints of the Zanfia Workspace API, with schemas and code samples.

12 min readLast updated Sep 10, 2026

Course content is addressed by the product id. Lesson and module statuses: draft, public, hidden, locked. Lesson content is Markdown and a PATCH replaces the whole body. Video lessons also carry chapters and key moments on their Bunny video (…/lessons/{lessonId}/video); the AI generate routes propose them from the transcript and you persist the picks with the same PUT. All routes require a Authorization: Bearer header — see Authentication.

Course structure

GET/products/{productId}/course

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

Response Body

application/json

application/json

curl -X GET "https://example.com/products/string/course"
{  "courseId": "string",  "modulesCount": 0,  "modules": [    {      "id": "string",      "name": "string",      "description": "string",      "status": "draft",      "lessonsCount": 0,      "lessons": [        {          "id": "string",          "title": "string",          "description": "string",          "type": "video",          "status": "draft",          "videoStatus": "Pending",          "length": 0,          "thumbnail": "string"        }      ]    }  ]}
{  "error": "string",  "message": "string"}

Course analytics

GET/products/{productId}/course/analytics

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

Query Parameters

learnersLimit?integer

Learner rows to return (default 50, max 200).

learnersSort?string

progress-desc (default), progress-asc (least progress first) or last-activity-desc.

Value in

  • "progress-desc"
  • "progress-asc"
  • "last-activity-desc"

Response Body

application/json

application/json

curl -X GET "https://example.com/products/string/course/analytics"
{  "summary": {    "tracked": 0,    "completedCourse": 0,    "activeLast7Days": 0,    "activeLast30Days": 0  },  "lessons": [    {      "lessonId": "string",      "title": "string",      "module": "string",      "status": "string",      "started": 0,      "completed": 0,      "quizAttempts": 0,      "quizPassed": 0    }  ],  "learners": {    "total": 0,    "returned": 0,    "lessonsBasis": 0,    "rows": [      {        "email": "string",        "name": "string",        "progressPercent": 0,        "completedLessons": 0,        "startedLessons": 0,        "completedCourse": true,        "numberOfSessions": 0,        "firstActivityAt": "string",        "lastActivityAt": "string"      }    ]  }}
{  "error": "string",  "message": "string"}

Course transcripts map

GET/products/{productId}/course/transcripts

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

Response Body

application/json

application/json

curl -X GET "https://example.com/products/string/course/transcripts"
{  "courseId": "string",  "modules": [    {      "id": "string",      "name": "string",      "lessons": [        {          "lessonId": "string",          "title": "string",          "type": "video",          "mediaId": "string",          "hasTranscript": true,          "transcriptionStatus": "string",          "durationSeconds": 0        }      ]    }  ],  "totals": {    "lessons": 0,    "videoLessons": 0,    "transcribed": 0  }}
{  "error": "string",  "message": "string"}

Lesson detail

GET/products/{productId}/course/lessons/{lessonId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Response Body

application/json

application/json

curl -X GET "https://example.com/products/string/course/lessons/string"
{  "courseId": "string",  "lesson": {    "id": "string",    "moduleId": "string",    "title": "string",    "description": "string",    "type": "video",    "status": "draft",    "content": "string",    "attachments": [      {        "uid": "string",        "name": "string",        "url": "string"      }    ],    "thumbnail": "string",    "video": {      "type": "bunny",      "status": "Pending",      "url": "string",      "length": 0    },    "audio": {      "url": "string",      "mimeType": "string",      "length": 0,      "size": 0    },    "createdAt": "string",    "updatedAt": "string"  }}
{  "error": "string",  "message": "string"}

Update a lesson

PATCH/products/{productId}/course/lessons/{lessonId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PATCH "https://example.com/products/string/course/lessons/string" \  -H "Content-Type: application/json" \  -d '{}'
{  "lessonId": "string"}
{  "error": "string",  "message": "string"}

Delete a lesson (permanent)

DELETE/products/{productId}/course/lessons/{lessonId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Response Body

application/json

application/json

curl -X DELETE "https://example.com/products/string/course/lessons/string"
{  "deleted": true}
{  "error": "string",  "message": "string"}

Add a module

POST/products/{productId}/course/modules

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X POST "https://example.com/products/string/course/modules" \  -H "Content-Type: application/json" \  -d '{    "name": "string"  }'
{  "moduleId": "string",  "name": "string"}
{  "error": "string",  "message": "string"}

Update a module

PATCH/products/{productId}/course/modules/{moduleId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

moduleId*string

Module id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PATCH "https://example.com/products/string/course/modules/string" \  -H "Content-Type: application/json" \  -d '{}'
{  "moduleId": "string"}
{  "error": "string",  "message": "string"}

Delete a module (permanent)

DELETE/products/{productId}/course/modules/{moduleId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

moduleId*string

Module id

Response Body

application/json

application/json

curl -X DELETE "https://example.com/products/string/course/modules/string"
{  "deleted": true}
{  "error": "string",  "message": "string"}

Add a lesson

POST/products/{productId}/course/modules/{moduleId}/lessons

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

moduleId*string

Module id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X POST "https://example.com/products/string/course/modules/string/lessons" \  -H "Content-Type: application/json" \  -d '{    "title": "string",    "type": "video"  }'
{  "lessonId": "string",  "moduleId": "string",  "title": "string"}
{  "error": "string",  "message": "string"}

Bulk lesson status change

POST/products/{productId}/course/lessons/status

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X POST "https://example.com/products/string/course/lessons/status" \  -H "Content-Type: application/json" \  -d '{    "lessonIds": [      "string"    ],    "status": "draft"  }'
{  "updated": 0}
{  "error": "string",  "message": "string"}

Reorder modules

PUT/products/{productId}/course/modules/order

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PUT "https://example.com/products/string/course/modules/order" \  -H "Content-Type: application/json" \  -d '{    "moduleIds": [      "string"    ]  }'
{  "courseId": "string"}
{  "error": "string",  "message": "string"}

Reorder a module's lessons

PUT/products/{productId}/course/modules/{moduleId}/lessons/order

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

moduleId*string

Module id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PUT "https://example.com/products/string/course/modules/string/lessons/order" \  -H "Content-Type: application/json" \  -d '{    "lessonIds": [      "string"    ]  }'
{  "moduleId": "string"}
{  "error": "string",  "message": "string"}

Set a lesson thumbnail

PUT/products/{productId}/course/lessons/{lessonId}/thumbnail

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PUT "https://example.com/products/string/course/lessons/string/thumbnail" \  -H "Content-Type: application/json" \  -d '{}'
{  "lessonId": "string",  "thumbnailUrl": "string"}
{  "error": "string",  "message": "string"}

Lesson video chapters & moments

GET/products/{productId}/course/lessons/{lessonId}/video

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Response Body

application/json

application/json

curl -X GET "https://example.com/products/string/course/lessons/string/video"
{  "lessonId": "string",  "chapters": [    {      "title": "string",      "start": 0,      "end": 0    }  ],  "moments": [    {      "label": "string",      "timestamp": 0    }  ],  "metaTags": [    {      "property": "string",      "value": "string"    }  ]}
{  "error": "string",  "message": "string"}

Save lesson video chapters & moments

PUT/products/{productId}/course/lessons/{lessonId}/video

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Presence-based: a list that is sent REPLACES the stored list, an omitted list is kept as is (the server fills it from the current video). At least one list required. metaTags are merged over Bunny's existing tags.

Response Body

application/json

application/json

curl -X PUT "https://example.com/products/string/course/lessons/string/video" \  -H "Content-Type: application/json" \  -d '{}'
{  "lessonId": "string",  "updated": true}
{  "error": "string",  "message": "string"}

Generate chapters (AI)

POST/products/{productId}/course/lessons/{lessonId}/chapters/generate

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

AI chapter proposal from the lesson's transcript — candidates only, nothing is persisted; save them with PUT …/lessons/{lessonId}/video.

Response Body

application/json

application/json

curl -X POST "https://example.com/products/string/course/lessons/string/chapters/generate" \  -H "Content-Type: application/json" \  -d '{}'
{  "chapters": [    {      "title": "string",      "start": 0,      "end": 0    }  ]}
{  "error": "string",  "message": "string"}

Generate key moments (AI)

POST/products/{productId}/course/lessons/{lessonId}/moments/generate

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X POST "https://example.com/products/string/course/lessons/string/moments/generate" \  -H "Content-Type: application/json" \  -d '{}'
{  "moments": [    {      "label": "string",      "timestamp": 0    }  ]}
{  "error": "string",  "message": "string"}

Quiz questions & settings

GET/products/{productId}/course/lessons/{lessonId}/quiz

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Response Body

application/json

application/json

curl -X GET "https://example.com/products/string/course/lessons/string/quiz"
{  "questions": [    {      "id": "string",      "question": "string",      "explanation": "string",      "points": 0,      "order": 0,      "mediaUrl": "string",      "source": {        "snippet": "string",        "startSeconds": 0      },      "type": "single_choice",      "options": [        {          "id": "string",          "text": "string",          "isCorrect": true,          "mediaUrl": "string"        }      ]    }  ],  "settings": {    "passingScore": 0,    "maxAttempts": 0,    "timeLimitSeconds": 0,    "shuffleQuestions": true,    "shuffleOptions": true,    "showCorrectAnswers": true,    "requirePassToProgress": true,    "questionCount": 0,    "totalPoints": 0  }}
{  "error": "string",  "message": "string"}

Add a quiz question

POST/products/{productId}/course/lessons/{lessonId}/quiz/questions

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X POST "https://example.com/products/string/course/lessons/string/quiz/questions" \  -H "Content-Type: application/json" \  -d '{    "question": {      "question": "string",      "type": "single_choice",      "options": [        {          "text": "string",          "isCorrect": true        }      ]    }  }'
{  "questionId": "string"}
{  "error": "string",  "message": "string"}

Reorder quiz questions

PUT/products/{productId}/course/lessons/{lessonId}/quiz/questions/order

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PUT "https://example.com/products/string/course/lessons/string/quiz/questions/order" \  -H "Content-Type: application/json" \  -d '{    "orderedQuestionIds": [      "string"    ]  }'
{  "reordered": true}
{  "error": "string",  "message": "string"}

Replace a quiz question

PATCH/products/{productId}/course/lessons/{lessonId}/quiz/questions/{questionId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

questionId*string

Quiz question id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PATCH "https://example.com/products/string/course/lessons/string/quiz/questions/string" \  -H "Content-Type: application/json" \  -d '{    "question": {      "question": "string",      "type": "single_choice",      "options": [        {          "text": "string",          "isCorrect": true        }      ]    }  }'
{  "updated": true}
{  "error": "string",  "message": "string"}

Delete a quiz question (permanent)

DELETE/products/{productId}/course/lessons/{lessonId}/quiz/questions/{questionId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

questionId*string

Quiz question id

Response Body

application/json

application/json

curl -X DELETE "https://example.com/products/string/course/lessons/string/quiz/questions/string"
{  "deleted": true}
{  "error": "string",  "message": "string"}

Update quiz settings

PATCH/products/{productId}/course/lessons/{lessonId}/quiz/settings

Authorization

bearerAuth
AuthorizationBearer <token>

API key from Dashboard → Integrations → API, MCP and CLI.

In: header

Path Parameters

productId*string

Product id

lessonId*string

Lesson id

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

curl -X PATCH "https://example.com/products/string/course/lessons/string/quiz/settings" \  -H "Content-Type: application/json" \  -d '{    "settings": {}  }'
{  "updated": true}
{  "error": "string",  "message": "string"}

Was this article helpful?

Related articles

Spotted something off? Tell us at support@zanfia.com.