Hint: It is normally preferable to import groups as a CSV file (possibly via the CSV Upload API), rather than directly interacting with the Groups API.
The Watershed Groups API is used by activity providers to create groups of people. These groups can be assigned permissions and you can aggregate data by group in reports. Many Watershed clients use groups to represent their organization’s hierarchy. This guide outlines the functional components of the API and provides an example.
As groups are comprised of people, the Groups API builds on the concepts of the People API. Make sure you are familiar with People before working with Groups. You will need to have people loaded into your organization before assigning them to groups.
Please note: This guide is designed to compliment a conversation with us. If you're looking to implement the Groups API and need assistance, please let us know and we will be glad to help.
Concepts
Groups
Groups are collections of people and other groups. They provide a way to model organization hierarchies, group users by roles or locations, define permissions, and filter report data. Groups have some associated metadata like name and type.
Group Types
Group Types allow you to define relationships between groups. Groups can be used for anything from representing hierarchies to defining learners' job roles to showing location of learners, so it's useful to define a Group Type for reporting and organization purposes. For instance, if you have groups for "Managers," "Directors," and "VPs," you make all of their Group Type be "Job Role." Each group has a group type and you need to create group types before creating groups of that type.
API
This section outlines the allowed resources and methods of the Groups API. In order to interact with the Groups API, you will need authentication credentials and an organization id (org id).
Hint: The Using Watershed's Administration APIs article provides important information on using the Groups API such as details on collections, paging, searching and sorting results.
Batch Updates
Whenever changes to groups and people are made that affect reporting, Watershed updates it's record of interaction data to reflect these changes. If you are making a lot of changes in rapid succession, it is better to let Watershed accumulate these changes and process them all at once after all of the changes have been submitted.
To delay the processing of groups or people changes until after all changes have been applied, add the parameter batch
with a value of true
to each request in the entire set of changes. Then, to process all pending people and group changes, send a batch update request as outlined below. The finish-batch-updates
request should only be sent once, after all groups and people changes have been requested.
Request URL: /api/organizations/[org-id]/groups/finish-batch-updates
Method: POST
Expected response code: 204 No Content
Please note: For smaller continuous updates, batch updates should not be used. Only use batch updates when making bulk updates.
Get a list of Group Types
Request URL: /api/organizations/[org-id]/group-types
Method: GET
Expected response code: 200 OK
Response:
Returns a Collection object containing an array of Group Type objects.
Get a Group Type by Id
Request URL: /api/organizations/[org-id]/group-types/[group-type-id]
Method: GET
Expected response code: 200 OK
Response:
Returns a Group Type object matching the requested id.
Create a Group Type
Request URL: /api/organizations/[org-id]/group-types
Method: POST
Expected response code: 200 OK
Request content:
A Group Type JSON object. Only the name property is required.
Response:
Returns the complete Group Type object created with all properties populated.
Update a Group Type
Request URL: /api/organizations/[org-id]/group-types/[group-type-id]
Method: PUT
Expected response code: 204 No Content
Request content:
A Group Type JSON object. Only the name property is required.
Response:
No content.
Delete a Group Type
Request URL: /api/organizations/[org-id]/group-types/[group-type-id]
Method: DELETE
Expected response code: 204 No Content
Response:
Returns the complete Group Type object deleted.
Get a List of Groups
Request URL: /api/organizations/[org-id]/groups
Method: GET
Expected response code: 200 OK
Request Parameters
Parameter |
Type |
Description |
rootOnly |
Boolean |
If true, only includes top level groups, i.e. those that have no parent. |
Response
Returns a Collection object containing an array of matching Group objects.
Get a Group by Id
Request URL: /api/organizations/[org-id]/groups/[group-id]
Method: GET
Expected response code: 200 OK
Hint: you can also get a group by their custom id using the request url /api/organizations/[org-id]/groups/?customId=[custom-id]
Request Parameters
Parameter |
Type |
Description |
childDepth |
Integer |
Defaults to zero. If a value other than zero is provided, the response will include data for child groups down to the depth specified, for example for a childDepth of 2, data about children of the group and those children’s children will be included. Use a childDepth of -1 to include all data. Please note: a complete list of child group ids will always be included in the response; use this parameter to get the data about those child groups without having to make additional API calls. |
parentDepth |
Integer |
Defaults to zero. If a value other than zero is provided, the response will include data for parent groups up to the depth specified, for example for a parentDepth of 2, data about parent of the group and that parent’s parent will be included. Use a parentDepth of -1 to include all data. Please note: a complete list of parent group ids will always be included in the response; use this parameter to get the data about those parent groups without having to make additional API calls. |
Response
Returns a Group object matching the requested id.
Get Multiple Groups by ID
Request URL: /api/organizations/[org-id]/groups/multi
Method: GET
Expected Response: 200 OK
Request Parameters
Parameter |
Type |
Description |
ids |
Array |
A list of the group ids you want to retrieve. |
customIds |
Array |
A list of the group customIds that you want to retrieve. This can be used as an alternative to providing ids. |
Response
Returns a Collection object containing an array of Group objects that match the ids passed as parameters.
Get Members by Group Id
Request URL: /api/organizations/[org-id]/groups/[group-id]/members
Method: GET
Expected response code: 200 OK
Response
Returns a Collection object containing an array of Person objects that belong to the group or child groups.
Create a Group
Request URL: /api/organizations/[org-id]/groups
Method: POST
Expected response code: 200 OK
Request Content
A JSON formatted Group object. This group object does not need to include ids or created timestamps.
Response
Returns the complete Group object created with all properties populated.
Update a Group
Request URL: /api/organizations/[org-id]/groups/[group-id]
Method: PUT
Expected response code: 204 No Content
Hint: you can also update a group by their custom id using the request url /api/organizations/[org-id]/groups/?customId=[custom-id]
Request content
A Group JSON object. This group object does not need to include ids or created timestamps.
Request Parameters
Parameter |
Type |
Description |
action=metadata_update |
- |
This parameter should be added to a query string when you just want to update the groups metadata (name, description, image) without changing it's membership or hierarchy information. |
Response
No content.
Update Multiple Groups
Request URL: /api/organizations/[org-id]/groups/multi
Method: PUT
Expected Response: 204 No Content
Request Content
A list of Group JSON objects. These group objects do not need to include ids or created timestamps.
Request Parameters
Parameter |
Type |
Description |
batch |
Boolean |
Defaults to false. Controls whether you want to update the groups as a batch. |
Response
No content.
Delete a Group
Request URL: /api/organizations/[org-id]/groups/[group]
Method: DELETE
Expected response code: 204 No Content
Hint: you can also delete a group by their custom id using the request url /api/organizations/[org-id]/groups/?customId=[custom-id]
Response
Returns the complete Group object deleted.
Entity Model
This section outlines the objects used in interacting with the Groups API.
Group Type
An object representing a type of group.
Property |
Type |
Description |
id |
Integer |
Watershed’s id for the group type. |
created |
ISO 8601 timestamp |
When the group type was created. |
name |
String |
The display name of the Group Type e.g. “Job Role”. |
displayOrder |
Integer |
The order the group type will be displayed in relative to other group types in a list. |
Group
An object representing a group.
Property |
Type |
Description |
id |
Integer |
Watershed’s id for the group. |
customId |
String |
A custom identifier for the Group, e.g. an identifier used in another system. Must be unique. |
created |
ISO 8601 timestamp |
When the group type was created. |
name |
String |
The display name of the Group e.g. “Accountant”. |
description |
String |
A longer description for the group. |
type |
GroupType |
The type of Group |
imageUrl |
URI |
A url for an image associated with this group. |
childGroupIds |
Array |
A list of group ids of the groups that are direct descendants of this group. |
childGroupCustomIds |
Array |
A list of customIds of the groups that are direct children of this group. |
childGroups |
Array |
A list of complete group objects for the groups that are direct children of this group. This property is read-only and only populated when requested via the childDepth query parameter. |
parentGroupIds |
Array |
A list of group ids of the groups that are direct parents of this group. |
parentGroupCustomIds |
Array |
A list of customIds of the groups that are direct parents of this group. |
parentGroups |
Array |
A list of complete group objects for the groups that are direct parents of this group. This property is read-only and only populated when requested via the parentDepth query parameter. |
peopleIds |
Array |
A list of person ids of people that are direct members of this group. People belonging to groups that are children of this group are not included. See Get Members by Group Id above for details of how to get a list of all people included in the group, both directly and indirectly. |
peopleCustomIds |
Array |
A list of person customIds of people that are direct members of this group. |
people |
Array |
A list of complete person objects for people that are direct members of this group. This property is read-only and only populated when requested via the childDepth query parameter. |
Example
Below we'll show some API interactions that correspond to an example scenario in which a simple organization hierarchy is impliented, along with another group outside of the hierarchy. Lets say we have a collection of ten people, within one organization, working under two divisions, development
and sales
.
Here's an example of one person, our friend Bob:
POST /people { "name": "Bob", "personas": [{ "name": "Bob", "mbox": "bob@example.com" },{ "name": "Bobby", "account": { "homePage": "http://example.com", "name": "bobby" } }] }
Please note: A person entity will be created automatically for each unique xAPI agent which is referenced in statements sent to the LRS. In such case, a single persona is associated with the person, which corresponds to the xAPI agent object present in the statement.
Assume we've created our ten people in the API and can now reference thi via ID. Let's create our three hierarchy groups, Company
, Sales
, and Development
, with sales
and development
as child groups of company
, and our ten people within the sales
and development
groups. We'll also create a group type called Team
to categorize these groups as organizational hierarchy groups.
Before we create our groups, let's create the group type they will all use, which we'll call "Team"
POST /group-types { "name": "Team" }
And now we can use that type as we create our groups (assuming our new group type has id 301):
POST /groups { "name": "Sales", "type": { "id": 301 }, "peopleIds": [ 1, 2, 3, 4 ] }
POST /groups { "name": "Development", "type": { "id": 301 }, "peopleIds": [ 5, 6, 7, 8, 9, 10 ] }
Assuming the prior groups were given IDs 1
and 2
on creation, we can reference thi as child groups when creating the top level group:
POST /groups { "name": "Company", "type": { "id": 301 }, "childGroupIds": [ 101, 102 ] }
We've created a small hierarchy, and we can now take a look at the whole thing in total by looking at the top level group and using the childDepth
parameter, passing the value of all
:
GET /groups/103?childDepth=all { "id": 103, "name": "Company", "type": { "id": 301, "name": "Team" }, "childGroupIds": [ 101, 102 ], "childGroups": [{ "id": 101, "name": "Sales", "type": { "id": 301, "name": "Team" }, "parentGroupIds": [ 103 ], "peopleIds": [ 1, 2, 3, 4 ], "people": [{ "id": 1, "name": "Bob", "personas": [{ "id": 1001, "name": "Bob", "mbox": "bob@example.com" },{ "id": 1002, "name": "Bobby", "account": { "homePage": "http://example.com", "name": "bobby" } }] },{ ... (more people entities) ... }] },{ "id": 102, "name": "Development", "type": { "id": 301, "name": "Team" }, "parentGroupIds": [ 103 ], "peopleIds": [ 5, 6, 7, 8, 9, 10 ], "people": [{ ... (more people entities here) ... }] }] }
We'll also create another group, which we'll call book-club
. This group is another top level group which exists outside of the organization hierarchy, and includes people which are part of the company book club:
POST /group-types { "name": "Club", }
POST /groups { "name": "Book Club", "type": { "id": 302 }, "peopleIds": [ 1, 4, 7, 8 ] }
As a final example, let's look at a single person and see their group ancestory, by using the parentDepth
parameter:
GET /people/1 { "id" 1, "name": "Bob", "personas": [{ "id": 1001, "name": "Bob", "mbox": "bob@example.com" },{ "id": 1002, "name": "Bobby", "account": { "homePage": "http://example.com", "name": "bobby" } }], "parentGroups": [{ "id": 101, "name": "Sales", "type": { "id": 301, "name": "Team" }, "parentGroupIds": [ 1 ], "parentGroups": [{ "id": 1, "name": "Company", "type": "team", "childGroupIds": [ 1, 2 ] }] },{ "id": 104, "name": "Book Club", "type": { "id": 302, "name": "Club" }, "peopleIds": [ 1, 4, 7, 8 ] }] }