This page describes the REST endpoints under /api/v1, authenticated with an organization-bound API key.
For OAuth clients and tools, see Connect with MCP.
Everything below applies to the REST API. Each endpoint page then documents only what is its own.
One header, on every request:
curl -H "x-api-key: $COHORTE_API_KEY" \
"https://your-school.cohorte.app/api/v1/enrollments/$ENROLLMENT_ID/timeline"A key belongs to one organization and one person. Cohorte resolves both from the key alone, and two checks follow, in this order:
member, admin or owner.
Some endpoints require a minimum; most do not, and delegate to the second
check.member of
the school: requiring admin on the wrapper would close endpoints to the very
people meant to call them. The domain policy has the last word, and each
endpoint page states it.Creating a key: Getting started.
Cohorte checks the holder's current account status on every request. A suspended
holder receives 401 Unauthorized, even with a valid key, before any domain
operation runs. A temporary suspension stops blocking access after its expiry;
the key must still be valid and the holder must still belong to the school.
Suspension does not permanently revoke the key.
The school is read from the key, never from the request. There is no
organizationId parameter, and sending one changes nothing.
An identifier that belongs to another school comes back 404 Not Found, not
403 — the API does not confirm that a resource it will not show you exists.
Every endpoint that changes something requires an Idempotency-Key header.
It is a value you choose — a UUID is the usual answer — and it must be stable
across retries of the same intent.
curl -X POST \
-H "x-api-key: $COHORTE_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"reason": "Parental leave"}' \
"https://your-school.cohorte.app/api/v1/enrollments/$ENROLLMENT_ID/pause"Replaying the same key returns the original result with replayed: true, and
writes nothing a second time — no duplicate event, no duplicate audit line, no
second notification.
Omitting the header on a command is a 400, deliberately: a retry without one is
a duplicate waiting to happen.
x-correlation-id is optional. Send one and it travels through the command, its
audit line and its domain events, then comes back in the response as
correlationId. Send none and Cohorte generates one.
It is what lets you find, in the audit trail, everything one run of your script caused.
A success is JSON, with success: true:
{
"success": true,
"data": {},
"correlationId": "b0e7f1c2-1d3a-4a52-9f77-52a4b7c3d1e0"
}A failure is JSON too: a human-readable error, and a stable code to branch
on.
{
"error": "The request is invalid.",
"code": "invalid_request",
"details": "title: String must contain at least 1 character(s)"
}Read code, never the sentence: the sentence is written for a human and may be
reworded or translated, the code will not change under you. details appears
only on invalid_request, because it is the only failure you fix by re-reading
what you sent.
| Code | Status |
|---|---|
invalid_request | 400 |
unauthorized | 401 |
forbidden | 403 |
not_found | 404 |
conflict | 409 |
internal_error | 500 |
An unexpected failure never describes itself: it answers internal_error and
nothing more. What happened is in Cohorte's logs, under the correlation id you
sent.
The status says what kind:
| Status | What it means |
|---|---|
400 Bad Request | The payload or a required header is wrong. The message names what. |
401 Unauthorized | Missing, unknown or expired key — or its holder is currently suspended or left the school. |
403 Forbidden | The key is valid, and its holder is not allowed to do this. |
404 Not Found | No such resource in this school. |
409 Conflict | The resource is not in a state that allows this command. |
500 Internal Server Error | Cohorte's fault. Retry with the same Idempotency-Key. |
Information
403 and 404 are not interchangeable. 403 means you may not, 404 means
there is nothing here for you — and a resource from another school always
gets the second, never the first.
Enrollments
Cohorts
Coaching sessions
Interventions
Live sessions
Programs
Courses
Sections
Lessons
Milestones
People
Delivery analytics
Sales availability
Community
Offer payments
Member tasks
Deliverables
Groups
Paths
Webhooks
Media
Bookings
My learning
Forms
Calendar connections
Offers
Responsibilities
Submission reviews
Closers
Personal preparation
Video library
Video questions
Booking administration, scoped commercial reads, coaching entry append, live detail and attendance are available through both the booking API and the MCP catalogue.
Personal preparation — private self profile and preparation shared across current roles.
Video library — video answers and replays the school team publishes; members read the published ones.
Video questions — members ask the team; the team assigns, answers with a library video, or cancels.