• Documentation
  • Introduction
    • The member journey
  • Training
    • Create a program
    • Courses and sections
    • Lessons, media and publication
    • Milestones and paths
    • Tasks and deliverables
    • Cohorts and groups
  • Student & Community
    • Joining a school
    • Learning and resuming
    • Submitting and revising work
    • Calendar and lives
    • Spaces and questions
    • Reading progress
  • Coaching
    • Roles and assignments
    • Member context and work queue
    • Reviews and feedback
    • Sessions and interventions
    • Cohort cockpit and live operations
  • Leads & Qualification
    • People, leads and applications
    • Contacts and import
    • Qualification forms
    • Application triage
  • Setting & Booking
    • Setter scope
    • Sales availability
    • Share a booking link
    • Prospect booking
    • Agenda and booking management
    • Prepare a call and share its meeting link
  • Closing, Offers & Payments
    • Closer scope
    • Compose an offer
    • Share a nominal payment link
    • Buyer checkout and access
    • Instalments
    • Offline payment
    • Track payment and access failures
    • Stripe school account
  • Administration & Integrations
    • Organization roles and domains
    • API keys and tenant binding
    • Webhooks
    • Payment setup
  • API quickstart
  • API reference
    • Connect with MCP
    • Enrollments
      • GETGet the enrollment timeline
      • GETGet the coaching briefing
      • POSTPause an enrollment
      • POSTResume an enrollment
      • POSTExtend a deadline
      • POSTTransfer an enrollment
      • POSTClose an enrollment
      • POSTSubmit an outcome measure
      • GETList outcome measures
      • GETList deadline extensions
      • DELETECancel a deadline extension
      • GETList enrollments
      • POSTEnroll a person
    • Cohorts
      • GETGet the cohort cockpit
      • GETList the enrollments behind a cockpit signal
      • PATCHConfigure a cohort
      • POSTMove a cohort to another phase
      • POSTCreate a cohort
      • POSTChange a cohort's status
    • Coaching sessions
      • GETList coaching sessions
      • GETGet a coaching session
      • POSTRecord a coaching session
      • POSTAppend coaching session entries
    • Interventions
      • GETList interventions
      • POSTPlan an intervention
      • POSTClose an intervention
    • Live sessions
      • PATCHRecord live attendance
      • GETList live attendance
      • GETRead one enrollment's attendance
      • GETList live sessions
      • POSTSchedule a live session
      • PATCHUpdate a live session
      • POSTCancel a live session
      • GETGet live session
    • Programs
      • GETList programs
      • POSTCreate a program
      • GETRead a program
      • PATCHUpdate a program
      • POSTArchive a program
      • POSTRestore a program
    • Courses
      • GETList the courses of a program
      • POSTCreate a course
      • PATCHUpdate a course
      • POSTRename a course
      • POSTArchive a course
      • POSTReorder the courses of a program
      • POSTUpload a course cover
    • Sections
      • GETList the sections of a course
      • POSTCreate a section
      • POSTRename a section
      • POSTDissolve a section
      • POSTReorder the sections of a course
      • POSTMove a lesson into a section
      • DELETETake a lesson out of its section
    • Lessons
      • GETList the lessons of a program
      • POSTCreate a lesson
      • GETRead a lesson
      • PATCHUpdate a lesson
      • POSTPublish a lesson
      • POSTArchive a lesson
      • POSTMove a lesson to another course
      • POSTReorder the lessons of a program
      • POSTAttach a resource
      • DELETEDetach a resource
      • POSTReorder the resources of a lesson
      • POSTUpload a lesson resource
      • POSTUpload a lesson video
      • GETRead a lesson by its identifier
      • PATCHUpdate a lesson by its identifier
      • GETRead the discussion of a lesson
      • POSTComment on a lesson
    • Milestones
      • GETList the milestones of a program
      • POSTCreate a milestone
      • PATCHUpdate a milestone
      • POSTArchive a milestone
      • POSTReorder the milestones of a program
      • GETList the contributions of a milestone
      • POSTAttach a contribution
      • DELETEDetach a contribution
    • People
      • POSTImport people
      • POSTLink a duplicate person
      • DELETEUnlink a duplicate person
    • Delivery analytics
      • GETGet delivery analytics
    • Sales availability
      • GETRead sales availability
      • GETPreview sales slots
      • PUTReplace sales availability
      • GETList eligible sales closers
    • Community
      • POSTUpload an attachment
      • POSTAttach to a thread
      • POSTCreate a space
      • POSTPost a thread
      • POSTReply to a thread
      • POSTLink a thread
      • GETList spaces
      • GETRead a thread
      • GETSearch the community
    • Offer payments
      • POSTPause automatic charging
      • DELETEResume automatic charging
      • POSTCharge an instalment now
      • GETGet collections dashboard
    • Member tasks
      • POSTCreate a member task
      • GETList the tasks of a milestone
      • PUTUpdate a member task
      • POSTArchive a member task
      • POSTReorder the tasks of a milestone
      • GETRead a task
      • GETList program tasks
    • Deliverables
      • POSTCreate a deliverable
      • GETList the deliverables of a task
      • GETGet a deliverable
      • PUTUpdate a deliverable
      • POSTArchive a deliverable
    • Groups
      • GETList groups
      • POSTCreate a group
      • GETGet a group
      • PATCHUpdate a group
      • POSTAdd a Group membership
      • DELETERemove a Group membership
    • Paths
      • GETList program paths
      • POSTCreate a path
      • GETGet a path
      • PATCHVersion or promote a path
    • Webhooks
      • GETList webhook subscriptions
      • POSTCreate a webhook subscription
      • GETGet a webhook subscription
      • PATCHUpdate a webhook subscription
      • DELETEDelete a webhook subscription
      • POSTVerify a webhook subscription
      • POSTRotate a webhook secret
      • POSTPause or reactivate a webhook subscription
      • GETList webhook deliveries
      • GETGet a webhook delivery
      • POSTReplay a webhook delivery
    • Media
      • GETList media
      • POSTUpload a media
      • PATCHRename a media
      • DELETEDelete a media
    • Bookings
      • GETList the open slots of a booking link
      • POSTSave a booking lead
      • POSTBook a call for a prospect
      • GETGet booking details
      • GETList bookings
      • GETGet booking
      • PATCHUpdate booking details
      • GETGet booking agenda
      • GETGet closer meeting link
      • GETList person bookings
      • PUTSet closer meeting link
      • GETList booking links
      • POSTSend a booking email
      • GETRead booking follow-up
      • POSTCreate booking link
      • GETGet booking link
      • PUTRecord booking attendance
      • GETRead booking reminder settings
      • PATCHUpdate booking link
      • POSTReschedule booking
      • PUTSet booking reminder settings
      • POSTCancel booking
      • GETList booking reassignment candidates
      • POSTReassign booking
      • GETList booking reschedule slots
      • GETList booking reassignment slots
    • My learning
      • GETList my enrollments
      • GETGet my learning context
      • GETList my lessons
      • GETGet one of my lessons
      • GETList my agenda
      • GETGet my lesson note
      • PUTSave my lesson note
      • DELETEDelete my lesson note
      • GETList my lesson notes
      • GETGet my lesson's agent section
      • GETList my tasks
      • GETRead my submission
      • POSTOpen my submission draft
      • PUTSave my submission draft
      • POSTSubmit my work
      • POSTResubmit my work
    • Forms
      • GETList forms
      • POSTCreate a form
      • GETGet a form
      • PATCHUpdate form identity
      • DELETEDelete a form
      • PUTSave form definition
      • PUTSet form theme
      • PUTSet form qualification
      • PUTSet submission mode
      • PUTOpen or close a form
      • POSTPublish a form
      • POSTUnpublish a form
      • GETList form responses
      • GETGet a form response
      • GETRead form statistics
      • POSTRetry response qualification
      • GETRead form definition
      • GETRead form theme
      • GETRead form qualification
      • GETRead form submission-settings
      • GETRead form identity fields
      • PUTSet form identity fields
    • Calendar connections
      • GETList calendar connections
      • GETRead a calendar connection
      • POSTRequest calendar consent
      • GETList writable calendars
      • PUTSelect a calendar
      • DELETEDisconnect a calendar
    • Offers
      • GETList offers
      • POSTCreate an offer
      • GETGet an offer
      • PATCHUpdate an offer
      • GETGet composer options
    • Responsibilities
      • GETList responsibilities
      • POSTAssign a responsibility
      • DELETERemove a responsibility
    • Submission reviews
      • GETList submission reviews
      • GETRead a submission review
      • POSTTake a submission in review
      • POSTDecide a submission review
    • Closers
      • GETList closer invitations
      • POSTInvite a closer
      • POSTResend a closer invitation
      • DELETECancel a closer invitation
      • GETRead commercial responsibility
      • PUTAssign commercial responsibility
      • GETRead my sales availability
      • PUTUpdate my sales availability
      • GETRead my closer setup
    • Personal preparation
      • GETRead my work profile
      • PATCHUpdate my work profile
      • GETRead my preparation
    • Video library
      • GETList video resources
      • GETGet a video resource
      • POSTPublish a video resource
      • PATCHUpdate a video resource
      • POSTUnpublish a video resource
      • POSTRepublish a video resource
    • Video questions
      • POSTAsk a question
      • GETList my questions
      • GETGet my question
      • GETList received questions
      • PATCHAssign a question
      • POSTAnswer a question
      • POSTCancel a question
  1. Documentation
  2. API reference
  3. Lessons
  4. Create a lesson
HomeBlogDocumentationPricingContact

Create a lesson

PreviousList the lessons of a programNextRead a lesson
On this page
AuthorizationPath parametersRequest headersRequest bodyExampleResponseExample responseAgent recipeNotesRelated

POST /api/v1/programs/{programId}/lessons

Writes a lesson. It is born a draft — invisible to members until published — and lands last in its scope: inside courseId if you give one, among the loose lessons of the program otherwise.

Resources can be attached in the same call, or later one by one.

Authorization

Role in the organizationThis endpoint
OWNERAllowed
ADMINAllowed
MEMBERRefused
RequirementRule for this endpoint
Business roleNone — writing content is the same gesture as composing the structure
Resource scopeProgram of the school attached to the API key
Resource stateAn archived program, or an archived course, answers 403

Path parameters

ParameterTypeRequiredDescription
programIdUUIDyesProgram visible from the key's school

Request headers

HeaderRequiredDescription
x-api-keyyesAPI key created for this school
Idempotency-KeyyesStable key for this creation intention
X-Correlation-IdnoCaller correlation id, returned or generated

Request body

FieldTypeRequiredNullableDescription
titlestringyesno3 to 160 characters
courseIdUUIDnoyesCourse of the same program. null leaves the lesson loose
contentstringnoyesMarkdown, up to 20 000 characters
videoUrlstringnoyesA Vimeo, YouTube or Bunny Stream link. Stored in canonical form
resourcesarraynonoUp to 50 resources, attached in the same transaction
externalIdstringnoyesYour stable identifier for the lesson, unique inside the program (case-insensitive): 1 to 32 letters, digits, ., -, _, starting with a letter or digit. null clears it
audiencestring[]nonoWho the lesson is for: up to 5 of all, freelance, employee, agency, saas. all cannot be combined. [] clears it
levelstringnoyesessential or deep_dive. null clears it
prerequisitesstring[]nonoUp to 20 externalIds of other lessons of the program (they may not exist yet). Never the lesson's own externalId. [] clears them
videoMinutesintegernoyesVideo duration in minutes, 1 to 600. null clears it
taskRefstringnoyesThe task this lesson counts for (e.g. T1.1), same format as externalId. null clears it

Each resource is {resourceType, title, url?, mediaId?, storagePath?, mimeType?, sizeBytes?}. A link needs url; a file needs a mediaId from the school's media library (or a storagePath in the folder of another lesson of the same school), which you get from Upload a lesson resource. A storagePath outside the school, or one where no file was uploaded, is a 400; a mediaId of another school is a 404. For a file, the url is not read: the address is always the one of its media.

Vimeo, YouTube and Bunny Stream videos play inside a lesson; another provider is refused with a message that says so, not silently stored.

json
{
  "title": "Structure a discovery call",
  "courseId": "9f2c0a1e-0000-4000-8000-000000000000",
  "content": "## The plan\n\nOpen with the outcome.",
  "videoUrl": "https://vimeo.com/912440188",
  "resources": [
    {"resourceType": "link", "title": "Call grid", "url": "https://example.com/grid"}
  ]
}

Example

bash
curl -X POST "$COHORTE_API_BASE_URL/api/v1/programs/$PROGRAM_ID/lessons" \
  -H "x-api-key: $COHORTE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"title":"Structure a discovery call","courseId":"'"$COURSE_ID"'"}'

Response

  • 201 Created — the lesson exists, as a draft.
  • 200 OK — the same Idempotency-Key replayed the original creation.
  • 400 Bad Request — missing Idempotency-Key, invalid JSON, a title outside 3–160 characters, a video from another provider, a link without url, a file with neither mediaId nor storagePath, a storagePath outside the school or with no uploaded file behind it, a media that is not a stored file, or more than 50 resources.
  • 401 Unauthorized — the key is missing, invalid, or no longer attached to a member.
  • 403 Forbidden — the bearer is not OWNER or ADMIN, or the program is archived.
  • 404 Not Found — the program is unknown, belongs to another school, courseId is not one of its courses, or a resource's mediaId is not a media of this school.
  • 409 Conflict — another lesson of the program already uses this externalId (comparison ignores case).

Example response

json
{
  "success": true,
  "replayed": false,
  "data": {
    "id": "8c3b1e72-6d4a-4a9f-b2e3-7c8d9e0f1a2b",
    "programId": "9f2c0a1e-4b7d-4c1a-9e3f-2a6b8c0d1e2f",
    "courseId": "3b8e2d41-7a6c-4f1e-8b25-9c0d1e2f3a4b",
    "sectionId": null,
    "title": "Structure a discovery call",
    "content": null,
    "videoUrl": null,
    "status": "draft",
    "position": 2,
    "createdAt": "2026-09-01T09:00:00.000Z",
    "updatedAt": "2026-09-01T09:00:00.000Z"
  },
  "correlationId": "0f6b1d92-5c3e-4a8b-9d71-3e2f4a6b8c10"
}

Agent recipe

  1. Create the lesson as a draft, with its text and video.
  2. Upload files and attach them as resources.
  3. Publish it — nothing is visible to members before that.

Notes

  • The lesson, its resources, the audit entry and the lesson.created event are written in one transaction.
  • No email or notification is sent by this endpoint.

Related

  • Publish a lesson
  • Attach a resource