🚀 Heads up: Our API Docs Have Moved!
We have relocated to Instructure Developer Documentation Portal. 🎉 Please update your bookmarks. This page will automatically redirect after July 1, 2026.

Cohorts API

Manage cohorts, groups of people placed in an account. Cohorts nest into trees up to a configurable depth, 10 by default.

A Cohort object looks like:

// A named group in a Canvas account.
{
  // the ID of the cohort
  "id": 4002,
  // the root account at the top of the account hierarchy the cohort is placed in
  "root_account_id": 1,
  // the root cohort of this cohort's tree; equal to id when the cohort is itself
  // a root
  "root_cohort_id": 4000,
  // the account the cohort is placed in, a root account or a sub-account
  "account_id": 1,
  // the cohort one level above this one, or null for a root cohort
  "parent_cohort_id": 4000,
  // the name of the cohort
  "name": "Mercy General Hospital",
  // free-text description of the cohort
  "description": "Acute care hospitals in the Mercy network.",
  // level in the hierarchy; a root cohort is 1
  "depth": 2,
  // the status of the cohort
  "workflow_state": "active",
  // the unique SIS identifier within the root account
  "sis_source_id": "HS-MERCY-GEN",
  // the SIS import that last touched the cohort, if any
  "sis_batch_id": 12,
  // fields last changed outside SIS; a later SIS import leaves these alone
  "stuck_sis_fields": ["name"],
  // when the cohort was created
  "created_at": "2026-01-15T10:00:00Z",
  // when the cohort was last updated
  "updated_at": "2026-01-15T10:00:00Z",
  // the number of active members; present with include[]=member_count
  "member_count": 25,
  // the number of active leaders; present with include[]=leader_count
  "leader_count": 2,
  // the number of active cohorts one level below; present with
  // include[]=child_count
  "child_count": 3,
  // the chain of cohorts from the root down to the parent, root first; present
  // with include[]=ancestors. Each ancestor carries the counts also requested in
  // include[]
  "ancestors": null
}

A CohortTreeNode object looks like:

// A cohort and the subtree beneath it.
{
  // the cohort at this node
  "cohort": null,
  // active direct children, newest first, capped at 100 per node
  "children": null,
  // true when this node has children that the requested depth cut off; fetch the
  // subtree again from this node to see them
  "truncated": false,
  // true when this node has more than 100 active direct children and children
  // holds only the first 100; list with parent_cohort_id set to this node's id
  // for the complete set; independent of truncated
  "children_truncated": false
}

List cohorts CohortsController#index

GET /api/v1/accounts/:account_id/cohorts

Scope: url:GET|/api/v1/accounts/:account_id/cohorts
List the cohorts placed directly in the account, or the direct children of one cohort. Results are paginated. Without parent_cohort_id, the caller needs account-level permission; cohort leaders get 401.

Request Parameters:

Parameter Type Description
roots boolean Only list cohorts with no parent. Can't be combined with parent_cohort_id.
parent_cohort_id integer List the direct children of a cohort placed in this account.
search_term string Only list cohorts whose name contains this text. Needs at least two characters.
sort string The field to sort by. Defaults to created_at.

Allowed values: created_at, name, workflow_state, depth

order string The sort direction. Defaults to desc. Ties break by id ascending.

Allowed values: asc, desc

workflow_state[] string Only list cohorts in these states. Defaults to active. "all" lists both states.

Allowed values: active, deleted, all

include[] string Extra data to compute for each cohort.

Allowed values: member_count, leader_count, child_count

per_page integer The number of cohorts per page. See the pagination section of the API documentation.
Returns a list of Cohort objects

List the cohorts I lead CohortsController#led

GET /api/v1/cohorts

Scope: url:GET|/api/v1/cohorts
List the top-level cohorts the caller leads across the root account. A led cohort is hidden when the caller also leads one of its active ancestors. With search_term, search instead covers every cohort the caller leads or that sits below an active cohort they lead, returned flat. This endpoint checks no permission of its own. Results are paginated.

Request Parameters:

Parameter Type Description
search_term string Search all cohorts the caller leads or that sit below an active cohort they lead, at any depth, and list those whose name contains this text, flat rather than top-level only. Needs at least two characters.
sort string The field to sort by. Defaults to created_at.

Allowed values: created_at, name, workflow_state, depth

order string The sort direction. Defaults to desc. Ties break by id ascending.

Allowed values: asc, desc

workflow_state[] string Only list cohorts in these states. Defaults to active. "all" lists both states.

Allowed values: active, deleted, all

include[] string Extra data to compute for each cohort.

Allowed values: member_count, leader_count, child_count

per_page integer The number of cohorts per page. See the pagination section of the API documentation.
Returns a list of Cohort objects

Get a cohort CohortsController#show

GET /api/v1/accounts/:account_id/cohorts/:cohort_id

Scope: url:GET|/api/v1/accounts/:account_id/cohorts/:cohort_id
Fetch one cohort by id. A soft-deleted cohort is still returned, with workflow_state "deleted". The cohort can be in any account under the root account; the account in the path is ignored.

Request Parameters:

Parameter Type Description
include[] string Extra data to compute for the cohort. "ancestors" adds the chain of cohorts from the root down to the parent, root first. Counts requested alongside "ancestors" are computed for each ancestor too, so one request tells which ancestors have more children to load.

Allowed values: member_count, leader_count, child_count, ancestors

Returns a Cohort object

Get cohort permissions CohortsController#permissions

GET /api/v1/accounts/:account_id/cohorts/:cohort_id/permissions

Scope: url:GET|/api/v1/accounts/:account_id/cohorts/:cohort_id/permissions
Returns permission information for the calling user on the given cohort. A soft-deleted cohort is still answered for callers who can view it. See also the Account counterpart.

Request Parameters:

Parameter Type Description
permissions[] string List of permissions to check against the authenticated user. Defaults to every cohort permission. Permission names are documented in the List assignable permissions endpoint.

Example Request:

curl https://<canvas>/api/v1/accounts/1/cohorts/4002/permissions \
  -H 'Authorization: Bearer <token>' \
  -d 'permissions[]=manage_cohorts_edit' \
  -d 'permissions[]=manage_cohorts_add_members'

Example Response:

{"manage_cohorts_edit": true, "manage_cohorts_add_members": false}

Get a cohort tree CohortsController#tree

GET /api/v1/accounts/:account_id/cohorts/:cohort_id/tree

Scope: url:GET|/api/v1/accounts/:account_id/cohorts/:cohort_id/tree
Fetch a cohort with its active descendants as a nested tree. Each node lists at most 100 children, newest first. The cohort can be in any account under the root account; the account in the path is ignored.

Request Parameters:

Parameter Type Description
depth integer How many levels to return, from 1 to 10. Defaults to 2.
Returns a CohortTreeNode object

List member candidates CohortsController#member_candidates

GET /api/v1/accounts/:account_id/cohorts/:cohort_id/member_candidates

Scope: url:GET|/api/v1/accounts/:account_id/cohorts/:cohort_id/member_candidates
List the users who can be added as members or leaders of a cohort, ordered by sortable name and paginated. With purpose "members" (the default) the caller needs manage_cohorts_add_members on the cohort and users who are already active members are left out. With purpose "leaders" the caller needs manage_cohorts_add_leaders and current members are included, since a member can be made a leader. An account admin with read_roster on the cohort's account sees the users of that account and its sub-accounts. A cohort leader whose role carries the purpose's permission sees the active members of the shallowest cohort they lead that contains this cohort, and of that cohort's sub-cohorts. The cohort can be in any account under the root account; the account in the path is ignored. Every caller can search by name. Searching by login, email, or SIS ID also needs the view_user_logins, read_email_addresses, or read_sis permission respectively.

Request Parameters:

Parameter Type Description
search_term string Only list users matching this text. Needs at least two characters.
purpose string What the picked users will be added as. Defaults to members.

Allowed values: members, leaders

per_page integer The number of users per page. See the pagination section of the API documentation.
Returns a list of User objects

List assignable leader roles CohortsController#assignable_roles

GET /api/v1/accounts/:account_id/cohorts/:cohort_id/assignable_roles

Scope: url:GET|/api/v1/accounts/:account_id/cohorts/:cohort_id/assignable_roles
List the cohort roles the caller may assign when adding a leader to a cohort, paginated. The caller needs manage_cohorts_add_leaders on the cohort. A role is assignable when every cohort permission it carries is one the caller holds on the cohort, so nobody can hand out a role broader than their own. The built-in Cohort Leader role comes first, then custom cohort roles by name. A deleted cohort returns 404.

Request Parameters:

Parameter Type Description
per_page integer The number of roles per page. See the pagination section of the API documentation.

Example Response:

[{ "id": 12, "label": "Cohort Leader", "base_role_type": "CohortLeader" }]

Create a cohort CohortsController#create

POST /api/v1/accounts/:account_id/cohorts

Scope: url:POST|/api/v1/accounts/:account_id/cohorts
Create a cohort in the account. Set cohort[parent_cohort_id] to null to create a root cohort, or to the id of an active cohort in the same account to create a sub-cohort under it. Sub-cohorts need permission to create cohorts on the parent; root cohorts need it on the account. Responds with 400 and error_code max_depth_exceeded when the parent is already at the depth limit, or max_cohorts_exceeded when the root account is at its active cohort limit.

Request Parameters:

Parameter Type Description
cohort[name] Required string The name of the cohort, up to 255 characters.
cohort[parent_cohort_id] Required integer The id of the parent cohort, or null to create a root cohort. The key must be present.
cohort[description] string Free-text description, up to 500 characters.
cohort[sis_source_id] string The SIS identifier, up to 255 characters and unique within the root account. Setting it requires the manage_sis permission.
Returns a Cohort object

Update a cohort CohortsController#update

PUT /api/v1/accounts/:account_id/cohorts/:cohort_id

Scope: url:PUT|/api/v1/accounts/:account_id/cohorts/:cohort_id
Change the name, description, or SIS identifier of a cohort. Send at least one of the three. The parent, account, and depth of a cohort never change. A deleted cohort cannot be updated.

Request Parameters:

Parameter Type Description
cohort[name] string The name of the cohort, up to 255 characters.
cohort[description] string Free-text description, up to 500 characters.
cohort[sis_source_id] string The SIS identifier, up to 255 characters and unique within the root account. Changing it requires the manage_sis permission.
override_sis_stickiness boolean Default is true. If false, name and description values that were last changed outside SIS ("sticky" fields, listed in stuck_sis_fields) are left as they are, and the other submitted fields are still applied.
Returns a Cohort object

Delete a cohort CohortsController#destroy

DELETE /api/v1/accounts/:account_id/cohorts/:cohort_id

Scope: url:DELETE|/api/v1/accounts/:account_id/cohorts/:cohort_id
Soft-delete a cohort and its memberships and leaders. Enrollments are not changed. Deleting an already deleted cohort succeeds without changes. Responds with 400 and error_code cohort_has_children when the cohort has active child cohorts. Returns a Cohort object