A group or clan brings together a bunch of users into a small community or team.
A group is made up of a superadmin, admins, and members. It can be public or private which determines whether it appears in results when a user lists groups. Private groups are similar to how WhatsApp groups work. A user can only be added when they’re invited to join by one of the group’s admins.
A group also has a maximum member count. This is set to 100 by default if the group is created by the client, or can be overridden if the group is created by the code runtime.
A group user has four states:
Code
Purpose
0
Superadmin
There must at least be 1 superadmin in any group. The superadmin has all the privileges of the admin and can additionally delete the group and promote admin members.
1
Admin
There can be one of more admins. Admins can update groups as well as accept, kick, promote, demote, ban or add members.
2
Member
Regular group member. They cannot accept join requests from new users.
3
Join request
A new join request from a new user. This does not count towards the maximum group member count.
Groups can be listed using a number of optional filters: name, lang_tag, open and (number of) members. If all filters are omitted, the operation will list all existing groups.
The name filter is case insensitive and mutually exclusive to the remainder filters. It can be useful to help the user look for a specific group by name, and it supports the % wildcard for partial matches as a suffix. As an example, looking for a group that is prefixed with the “Persian” word would be written as persian% name filter.
The remainder filters can be combined or omitted in any way, for instance, we could use the open and members filters to list all open groups with at most the specified amount of members.
Client
1
2
constgroups=awaitclient.listGroups(session,"heroes%",20);// fetch first 20 groups
console.info("List of groups:",groups);
Client
1
2
3
4
5
6
7
// Filter for group names which start with "heroes"conststringnameFilter="heroes%";varresult=awaitclient.ListGroupsAsync(session,nameFilter,20);foreach(varginresult.Groups){System.Console.WriteLine("Group name '{0}' count '{1}'",g.Name,g.EdgeCount);}
Client
1
2
3
4
5
6
7
8
9
10
11
autosuccessCallback=[this](NGroupListPtrlist){for(auto&group:list->groups){std::cout<<"Group name '"<<group.name<<"' count "<<group.edgeCount<<std::endl;}};// Filter for group names which start with "heroes"
// fetch first 20 groups
client->listGroups(session,"heroes%",20,"",successCallback);
Client
1
2
3
4
5
6
7
// Filter for group names which start with "heroes"
StringnameFilter="heroes%";GroupListgroups=client.listGroups(session,nameFilter,20).get();for(Groupgroup:groups.getGroupsList()){System.out.format("Group name %s count %s",group.getName(),group.getEdgeCount());}
Client
1
2
3
4
5
6
7
8
9
varlist:NakamaAPI.ApiGroupList=yield(client.list_groups_async(session,"heroes*",20),"completed")iflist.is_exception():print("An error occurred: %s"%list)returnforginlist.groups:vargroup=gasNakamaAPI.ApiGroupprint("Group: name %s, id %s",[group.name,group.id])
The message response for a list of groups contains a cursor. The cursor can be used to quickly retrieve the next set of results.
Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/group?limit=20&name=heroes%25&cursor=somecursor"\
-H 'Authorization: Bearer <session token>'
Client
1
2
constgroups=awaitclient.listGroups(session,"heroes%",20,cursor);console.info("List of groups:",groups);
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Filter for group names which start with "heroes"conststringnameFilter="heroes%";varresult=awaitclient.ListGroupsAsync(session,nameFilter,20);// If there are more results get next page.if(result.Cursor!=null){result=awaitclient.ListGroupsAsync(session,nameFilter,20,result.Cursor);foreach(varginresult.Groups){System.Console.WriteLine("Group name '{0}' count '{1}'",g.Name,g.EdgeCount);}}
voidYourClass::processGroupList(NGroupListPtrlist){for(auto&group:list->groups){std::cout<<"Group name '"<<group.name<<"' count "<<group.edgeCount<<std::endl;}if(!list->cursor.empty()){// request next page
requestHeroes(list->cursor);}}voidYourClass::requestHeroes(conststring&cursor){// Filter for group names which start with "heroes"
// fetch first 20 groups
client->listGroups(session,"heroes%",20,cursor,std::bind(&YourClass::processGroupList,this,std::placeholders::_1));}
Client
1
2
3
4
5
6
7
8
9
10
11
// Filter for group names which start with "heroes"
StringnameFilter="heroes%";GroupListgroups=client.listGroups(session,nameFilter,20).get();if(groups.getCursor()!=null){groups=client.listGroups(session,nameFilter,20,groups.getCursor()).get();for(Groupgroup:groups.getGroupsList()){System.out.format("Group name %s count %s",group.getName(),group.getEdgeCount());}}
varlist:NakamaAPI.ApiGroupList=yield(client.list_groups_async(session,"heroes*",20),"completed")iflist.is_exception():print("An error occurred: %s"%list)returnforginlist.groups:vargroup=gasNakamaAPI.ApiGroupprint("Group: name %s, id %s",[group.name,group.id])varcursor=list.cursorwhilecursor:# While there are more results get next page.list=yield(client.list_groups_async(session,"heroes*",20,cursor),"completed")iflist.is_exception():print("An error occurred: %s"%list)returnforginlist.groups:vargroup=gasNakamaAPI.ApiGroupprint("Group: name %s, id %s",[group.name,group.id])cursor=list.cursor
When a user has found a group to join they can request to become a member. A public group can be joined without any need for permission while a private group requires a superadmin or an admin to accept the user.
When a user joins or leaves a group event messages are added to chat history. This makes it easy for members to see what’s changed in the group.
curl -X POST "http://127.0.0.1:7350/v2/group/<group id>/join"\
-H 'Authorization: Bearer <session token>'
Client
1
2
3
constgroup_id="<group id>";awaitclient.joinGroup(session,group_id);console.info("Sent group join request",group_id);
Client
1
2
3
conststringgroupId="<group id>";awaitclient.JoinGroupAsync(session,groupId);System.Console.WriteLine("Sent group join request '{0}'",groupId);
Client
1
2
3
4
5
6
7
autosuccessCallback=[](){std::cout<<"Sent group join request"<<std::endl;};stringgroup_id="<group id>";client->joinGroup(session,group_id,successCallback);
Client
1
2
3
Stringgroupid="<group id>";client.joinGroup(session,groupid).get();System.out.format("Sent group join request %s",groupid);
Client
1
2
3
4
5
6
7
8
vargroup_id="<group id>"varjoin:NakamaAsyncResult=yield(client.join_group_async(session,group_id),"completed")ifjoin.is_exception():print("An error occurred: %s"%join)returnprint("Sent group join request %s"%group_id)
localgroup_id="<group_id>"localresult=nakama.join_group(client,group_id)ifresult.errorthenprint(result.message)returnendprint("Sent group join request",group_id)
The user will receive an in-app notification when they’ve been added to the group. In a private group an admin or superadmin will receive a notification when a user has requested to join.
Each user can list groups they’ve joined as a member or an admin or a superadmin. The list also contains groups which they’ve requested to join but not been accepted into yet.
Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/user/<user id>/group"\
-H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
6
7
8
constuserId="<user id>";constgroups=awaitclient.listUserGroups(session,userid);groups.user_groups.forEach(function(userGroup){console.log("Group: name '%o' id '%o'.",userGroup.group.name,userGroup.group.id);// group.State is one of: SuperAdmin, Admin, Member, or Join.
console.log("Group's state is %o.",userGroup.state);});
Client
1
2
3
4
5
6
7
8
conststringuserId="<user id>";varresult=awaitclient.ListUserGroupsAsync(session,userId);foreach(varuginresult.UserGroups){varg=ug.Group;System.Console.WriteLine("Group '{0}' role '{1}'",g.Id,ug.State);}
Client
1
2
3
4
5
6
7
8
9
10
autosuccessCallback=[](NUserGroupListPtrlist){for(auto&userGroup:list->userGroups){std::cout<<"Group name "<<userGroup.group.name<<std::endl;}};stringuserId="<user id>";client->listUserGroups(session,userId,{},{},{},successCallback);
Client
1
2
3
4
5
6
Stringuserid="<user id>";UserGroupListuserGroups=client.listUserGroups(session,userid).get();for(UserGroupList.UserGroupuserGroup:userGroups.getUserGroupsList()){System.out.format("Group name %s role %d",userGroup.getGroup().getName(),userGroup.getState());}
Client
1
2
3
4
5
6
7
8
9
10
varuser_id="<user id>"varresult:NakamaAPI.ApiUserGroupList=yield(client.list_user_groups_async(session,user_id),"completed")ifresult.is_exception():print("An error occurred: %s"%result)returnforuginresult.user_groups:varg=ug.groupasNakamaAPI.ApiGroupprint("Group %s role %s",g.id,ug.state)
A user can list all members who’re part of their group. These include other users who’ve requested to join the private group but not been accepted into yet.
Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/group/<group id>/user"\
-H 'Authorization: Bearer <session token>'
Client
1
2
3
constgroup_id="<group id>";constusers=awaitclient.listGroupUsers(session,group_id);console.info("Users in group:",users);
Client
1
2
3
4
5
6
7
conststringgroupId="<group id>";varresult=awaitclient.ListGroupUsersAsync(session,groupId);foreach(varuginresult.UserGroups){varg=ug.Group;System.Console.WriteLine("group '{0}' role '{1}'",g.Id,ug.State);}
Client
1
2
3
4
5
6
7
autosuccessCallback=[](NGroupUserListPtrlist){std::cout<<"Users in group: "<<list->groupUsers<<std::endl;};stringgroup_id="<group id>";client->listGroupUsers(session,group_id,{},{},{},successCallback);
Client
1
2
3
4
5
6
Stringgroupid="<group id>";GroupUserListgroupUsers=client.listGroupUsers(session,groupid).get();for(GroupUserList.GroupUsergroupUser:groupUsers.getGroupUsersList()){System.out.format("Username %s role %d",groupUser.getUser().getUsername(),groupUser.getState());}
Client
1
2
3
4
5
6
7
8
9
10
vargroup_id="<group id>"varmember_list:NakamaAPI.ApiGroupUserList=yield(client.list_group_users_async(session,group_id),"completed")ifmember_list.is_exception():print("An error occurred: %s"%member_list)returnforuginmember_list.group_users:varu=ug.userasNakamaAPI.ApiUserprint("User %s role %s"%[u.id,ug.state])
A group can be created with a name and other optional fields. These optional fields are used when a user lists and filter groups. The user who creates the group becomes the owner and a superadmin for it.
When a group has been created it’s admins can update optional fields.
Client
1
2
3
4
5
curl -X PUT "http://127.0.0.1:7350/v2/group/<group id>"\
-H 'Authorization: Bearer <session token>'\
-d '{
"description": "Better than Marvel Heroes!",
}'
Client
1
2
3
4
constgroup_id="<group id>";constdescription="Better than Marvel Heroes!";constgroup=awaitclient.updateGroup(session,group_id,{description:description});console.info("Updated group:",group);
Client
1
2
3
4
conststringgroupId="<group id>";conststringdesc="Better than Marvel Heroes!";vargroup=awaitclient.UpdateGroupAsync(session,groupId,null,desc);System.Console.WriteLine("Updated group: {0}",group);
Client
1
2
3
4
5
6
7
8
autosuccessCallback=[](){std::cout<<"Updated group"<<std::endl;};stringgroup_id="<group id>";stringdescription="Better than Marvel Heroes!";client->updateGroup(session,group_id,opt::nullopt,description,opt::nullopt,opt::nullopt,opt::nullopt,successCallback);
Client
1
2
3
4
Stringgroupid="<group id>";Stringdesc="Better than Marvel Heroes!";client.updateGroup(session,groupid,null,desc).get();System.out.format("Updated group %s",groupid);
Client
1
2
3
4
5
6
7
8
9
vargroup_id="<group id>"vardescription="Better than Marvel Heroes!"varupdate:NakamaAsyncResult=yield(client.update_group_async(session,group_id,null,description),"completed")ifupdate.is_exception():print("An error occurred: %s"%update)returnprint("Updated group")
Client
1
2
3
4
5
6
7
8
PUT /v2/group/<group id>
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{"description": "I was only kidding. Basil sauce ftw!",
}
Client
1
2
3
4
5
6
7
8
9
10
11
localgroup_id="<group id>"localrequest={description="I was only kidding. Basil sauce ftw!",}localresult=nakama.update_group(client,group_id,request)ifresult.errorthenprint(result.message)end
Updating a group’s size is an action that can only be performed authoritatively via the server.
Server
1
2
3
4
5
6
7
8
localnk=require("nakama")localnew_max_size=50localsuccess,err=pcall(nk.group_update("<GroupId>",nil,"","","","","",nil,nil,new_max_size))if(notsuccess)thennk.logger_error(("Could not update group: %q"):format(err))end
A user can leave a group and will no longer be able to join group chat or read message history. If the user is a superadmin they will only be able to leave when at least one other superadmin exists in the group.
Any user who leaves the group will generate an event message in group chat which other members can read.
Client
1
2
curl -X POST "http://127.0.0.1:7350/v2/group/<group id>/leave"\
-H 'Authorization: Bearer <session token>'
Each group is managed by one or more superadmins or admins. These users are members with permission to make changes to optional fields, accept or reject new members, remove members or other admins, and promote other members as admins.
A group must have at least one superadmin. The last superadmin has to promote another member before they can leave.
When a user joins a private group it will create a join request until an admin accepts or rejects the user. The superadmin or admin can accept the user into the group.
autosuccessCallback=[](){std::cout<<"added user to group"<<std::endl;};stringgroup_id="<group id>";stringuser_id="<user id>";client->addGroupUsers(session,group_id,{user_id},successCallback);
The user will receive an in-app notification when they’ve been added to the group. In a private group an admin will receive a notification about the join request.
To reject the user from joining the group you should kick them.
An admin can promote another member of the group as an admin. This grants the member the same privileges to manage the group. A group can have one or more admins.
autosuccessCallback=[](){std::cout<<"user has been promoted"<<std::endl;};stringgroup_id="<group id>";stringuser_id="<user id>";client->promoteGroupUsers(session,group_id,{user_id},successCallback);
An admin can demote another member of the group down a role. This revokes the member of his current privileges to and assigns member the privileges available in the demoted role. Members who are already at the lowest role in their group will not be affected by a demotion.
Code snippet for this language C++/Unreal/Cocos2d-x has not been found. Please choose another language to show equivalent examples.
An admin or superadmin can kick a member from the group. The user is removed but can re-join again later unless the user is banned or the group is private in which case an admin must accept the re-join request.
If a user is removed from a group it does not prevent them from joining other groups. Sometimes a bad user needs to be kicked from the group and banned from re-joining either the group or the whole server. This will prevent the user from being able to connect to the server and interact at all.
autosuccessCallback=[](){std::cout<<"user has been kicked"<<std::endl;};stringgroup_id="<group id>";stringuser_id="<user id>";client->kickGroupUsers(session,group_id,{user_id},successCallback);
A group can only be removed by one of the superadmins which will disband all members. When a group is removed it’s name can be re-used to create a new group.