GET /api/v1/programs/{programId}/lessons
Returns every lesson of a program, all statuses included. The operator view shows drafts: that is what makes them editable. What a member is allowed to see is a different question, and this endpoint does not answer it.
| Role in the organization | This endpoint |
|---|---|
OWNER | Allowed |
ADMIN | Allowed |
MEMBER | Conditional — with the program_director business role scoped to the organization, or as coach of this program |
| Parameter | Type | Required | Description |
|---|---|---|---|
programId | UUID | yes | Program visible from the key's school |
| Header | Required | Description |
|---|---|---|
x-api-key | yes | API key created for this school |
X-Correlation-Id | no | Caller correlation id, returned or generated |
curl "$COHORTE_API_BASE_URL/api/v1/programs/$PROGRAM_ID/lessons" \
-H "x-api-key: $COHORTE_API_KEY"200 OK — the list, possibly empty.400 Bad Request — programId is not a UUID.401 Unauthorized — the key is missing, invalid, or no longer attached to a member.403 Forbidden — the bearer is not OWNER, ADMIN, an organization-scoped program_director of this school, nor the coach of this program.| Field | Type | Nullable | Description |
|---|---|---|---|
success | boolean | no | true for a successful request |
data[].id | UUID | no | Lesson identifier |
data[].programId | UUID | no | Program that holds the lesson |
data[].courseId | UUID | yes | Course, or null for a lesson loose in the program |
data[].sectionId | UUID | yes | Section inside the course, or null |
data[].title | string | no | Lesson title |
data[].content | string | yes | Markdown body |
data[].videoUrl | string | yes | Canonical Vimeo, YouTube or Bunny Stream address, or null |
data[].status | string | no | draft, published or archived |
data[].position | integer | no | Rank inside its course, or inside the program |
data[].externalId | string | yes | Your identifier for the lesson, unique inside the program |
data[].audience | string[] | no | all, freelance, employee, agency, saas — empty when not set |
data[].level | string | yes | essential or deep_dive |
data[].prerequisites | string[] | no | externalIds of the lessons to read first |
data[].videoMinutes | integer | yes | Video duration in minutes |
data[].taskRef | string | yes | The task this lesson counts for |
data[].createdAt | ISO 8601 string | no | Creation time, in UTC |
data[].updatedAt | ISO 8601 string | no | Last change, in UTC |
correlationId | UUID | no | Correlation id for support |
Resources are not in the list — read one lesson to get them.
{
"success": true,
"data": [
{
"id": "5d9f3a60-1c2b-4e7d-8f4a-6b7c8d9e0f1a",
"programId": "9f2c0a1e-4b7d-4c1a-9e3f-2a6b8c0d1e2f",
"courseId": "3b8e2d41-7a6c-4f1e-8b25-9c0d1e2f3a4b",
"sectionId": "c41e7b03-9d2a-4e6f-b1c8-5a6b7c8d9e0f",
"title": "Structure a discovery call",
"content": "## Why it matters\n\nA discovery call decides the rest of the sale.",
"videoUrl": "https://vimeo.com/912440188",
"status": "published",
"position": 1,
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-04T17:12:00.000Z"
},
{
"id": "8c3b1e72-6d4a-4a9f-b2e3-7c8d9e0f1a2b",
"programId": "9f2c0a1e-4b7d-4c1a-9e3f-2a6b8c0d1e2f",
"courseId": "3b8e2d41-7a6c-4f1e-8b25-9c0d1e2f3a4b",
"sectionId": null,
"title": "Handle objections",
"content": null,
"videoUrl": null,
"status": "draft",
"position": 2,
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-04T17:12:00.000Z"
}
],
"correlationId": "0f6b1d92-5c3e-4a8b-9d71-3e2f4a6b8c10"
}