GET /api/v1/cohorts/{cohortId}/cockpit/enrollments
Returns the enrollments that compose one signal of the cohort cockpit, with the reason each one was classified that way and the date of its last intervention. This is how every counter of the cockpit is opened and explained.
| Role in the organization | This endpoint |
|---|---|
OWNER | Allowed — the whole cohort |
ADMIN | Allowed — the whole cohort |
MEMBER | Conditional — only with a business role below |
| Requirement | Rule for this endpoint |
|---|---|
| Business role | program_director scoped to the organization, or coach scoped to enrollments |
| Resource scope | Cohort of the organization attached to the API key |
| Participation | A coach lists only the enrollments of this cohort they are assigned to |
| Resource state | None |
| Parameter | Type | Required | Description |
|---|---|---|---|
cohortId | UUID | yes | Cohort visible from the key's organization |
| Parameter | Type | Required | Description |
|---|---|---|---|
signal | string | yes | on_time, late, at_risk, unknown, reviews, blockers, absences or no_intervention |
signal has no default: a missing or unknown value is refused with 400, so a
caller never receives a list they did not ask for.
curl "$COHORTE_API_BASE_URL/api/v1/cohorts/COHORT_ID/cockpit/enrollments?signal=late" \
-H "x-api-key: $COHORTE_API_KEY"200 OK — the enrollments behind the signal, possibly an empty list.400 Bad Request — signal is missing or is not one of the accepted values.401 Unauthorized — the key is missing, invalid, or no longer attached to a member.404 Not Found — the cohort is unknown, belongs to another organization, or the bearer has no scope on it.| Field | Type | Nullable | Description |
|---|---|---|---|
success | boolean | no | true for a successful request |
data.signal | string | no | The signal that was requested |
data.scope | string | no | tenant or assigned, the set the list covers |
data.enrollments[].enrollmentId | UUID | no | Enrollment identifier, the key of the member record |
data.enrollments[].firstName | string | no | Member first name |
data.enrollments[].lastName | string | yes | Member last name |
data.enrollments[].email | string | yes | Member email, null when the person has none |
data.enrollments[].status | string | no | pending, active or completed |
data.enrollments[].rhythm | string | no | on_time, late, at_risk or unknown |
data.enrollments[].reason | string | no | Why the rhythm was assigned; see the table below |
data.enrollments[].overdueSince | ISO 8601 string | yes | The missed deadline behind the verdict, when there is one |
data.enrollments[].lastInterventionAt | ISO 8601 string | yes | Last note or coaching session, null when there is none |
reason is a stable key, never a sentence: urgent_blocker,
repeated_absence, blocked_and_late, overdue_action, overdue_review,
not_active, no_active_action or on_track.
{
"success": true,
"data": {
"signal": "unknown",
"scope": "assigned",
"enrollments": [
{
"enrollmentId": "4af4cd8d-0000-4000-8000-000000000000",
"firstName": "Tom",
"lastName": "Girard",
"email": "tom@example.com",
"status": "active",
"rhythm": "unknown",
"reason": "no_active_action",
"overdueSince": null,
"lastInterventionAt": "2026-08-28T09:12:00.000Z"
}
]
}
}Read the cockpit first, then open the counter that is not zero: the two calls share the same scope and the same clock, so the list always adds up to the counter it explains.
curl "$COHORTE_API_BASE_URL/api/v1/cohorts/COHORT_ID/cockpit" \
-H "x-api-key: $COHORTE_API_KEY"
curl "$COHORTE_API_BASE_URL/api/v1/cohorts/COHORT_ID/cockpit/enrollments?signal=at_risk" \
-H "x-api-key: $COHORTE_API_KEY"absences returns an empty list while attendance has never been recorded; the
cockpit reports that source as unavailable rather than as zero.