Teams #

The Teams API reference for Unity provides a complete catalog of functions for implementing collaborative team features. All documented functions share common authentication patterns, operate within team-scoped contexts, and maintain consistent parameter structures for managing team resources, competitive events, and shared progression systems. Learn more in the Teams concept guide.

Teams API #

The core Teams API is used to create teams, manage membership, handle join requests, and send chat messages.

Core Function Reference #

FunctionDescription
TeamsSystemInitializes the teams system
RefreshAsyncRefreshes the teams system with latest data from server
CreateTeamAsyncCreates a new team
ListTeamsAsyncLists available teams by location
SearchTeamsAsyncSearches for teams by name/shortcode
JoinTeamAsyncJoins a team (by ID or Team object)
GetTeamMembersAsyncGets members of specified team
ApproveJoinRequestAsyncApproves a single join request
ApproveJoinRequestsAsyncApproves multiple join requests
RejectJoinRequestAsyncRejects a single join request
RejectJoinRequestsAsyncRejects multiple join requests
PromoteUsersAsyncPromotes team members to admin
LeaveTeamAsyncLeaves a team (by ID or Team object)
DeleteTeamAsyncDeletes a team
SendChatMessageAsyncSends a chat message to team
CancellationToken
Unless stated otherwise, all functions accept an optional CancellationToken which may be used to cancel the request.

Initialization #

The teams system relies on the Nakama System and an ILogger, both must be passed in as dependencies via the constructor.

1
2
var teamsSystem = new TeamsSystem(logger, nakamaSystem);
systems.Add(teamsSystem);

Subscribe to changes #

You can listen for changes in the teams system so that you can respond appropriately, such as updating the UI, by implementing the IObserver pattern, or use the SystemObserver<T> type which handles it for you.

1
2
3
4
5
var disposer = SystemObserver<TeamsSystem>.Create(teamsSystem, system => {
    Instance.Logger.Info($"System updated.");

    // Update UI elements etc as necessary here...
});

Refresh the teams system #

To ensure the teams system has the latest information from Nakama you can refresh it.

1
await teamsSystem.RefreshAsync();

Get current team #

Get the user’s current team.

1
2
var team = teamsSystem.Team;
Debug.Log($"Current Team: {team.Name}. Total members: {team.EdgeCount}");

Also determine if the user is an Admin or Superadmin of their current team.

1
2
var isAdmin = teamsSystem.IsAdmin;
var isSuperAdmin = teamsSystem.IsSuperAdmin;

Get current team members #

Get the user’s current team members.

1
2
3
4
5
6
foreach (var teamMemberKvp in teamsSystem.TeamMembers)
{
    var teamMember = teamMemberKvp.Value;
    var online = teamMember.User.Online ? "Online" : "Offline";
    Debug.Log($"{teamMember.User.Username} ({online})");
}

Get team members from other teams #

Get the team members in other teams by passing the team id or a team object.

1
2
var memberList = await teamsSystem.GetTeamMembersAsync("<teamId>");
var memberList = await teamsSystem.GetTeamMembersAsync(team);

Get chat history #

Get the chat history for the user’s team.

1
2
3
4
foreach (var message in teamsSystem.ChatHistory)
{
    Debug.Log($"{message.User.Username}: {message.Content}");
}

Create a team #

Create a team for the user.

1
2
3
4
5
6
var name = "MyTeam";
var description = "My team description";
var open = true;
var icon = "<iconUrl>";
var setupMetadata = "{}"; // Must be a valid JSON string.
var team = await teamsSystem.CreateTeamAsync(name, description, open, icon, setupMetadata);

List available teams #

List available teams by location.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var location = "uk";
var limit = 10;
var cursor = "<optionalCursor>";

var teamList = await teamsSystem.ListTeamsAsync(location, limit, cursor);

foreach (var team in teamList.Teams)
{
    Debug.Log($"Team: {team.Name}. Total members: {team.EdgeCount}");
}

Search for teams #

Search for teams based on their name or shortcode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var name = "<name>";
var shortcode = "<optionalShortcode>";
var limit = 10;

var teamList = await teamsSystem.SearchTeamsAsync(name, shortcode, limit);

foreach (var team in teamList.Teams)
{
    Debug.Log($"Team: {team.Name}. Total members: {team.EdgeCount}");
}

Join a team #

Join a team for the user either by passing the team id or by passing a team object.

1
2
await teamsSystem.JoinTeamAsync("<teamId>");
await teamsSystem.JoinTeamAsync(team);

List join requests #

List join requests for the user’s current team

1
2
3
4
foreach (var joinRequest in teamsSystem.JoinRequests)
{
    Debug.Log($"{joinRequest.User.Username} requested to join.");
}

Approve join requests #

Approve a single join request, either by passing the user id of the user requesting to join, or by directly passing the group user object.

1
2
await teamsSystem.ApproveJoinRequestAsync("<teamId>", "<userId>");
await teamsSystem.ApproveJoinRequestAsync("<teamId>", groupUser);

Also approve multiple join requests at once.

1
await teamsSystem.ApproveJoinRequestsAsync("<teamId>", new[] { "<userId1>", "<userId2>" });

Reject join requests #

Reject a single join request, either by passing the user id of the user requesting to join, or by directly passing the group user object.

1
2
await teamsSystem.RejectJoinRequestAsync("<teamId>", "<userId>");
await teamsSystem.RejectJoinRequestAsync("<teamId>", groupUser);

Also reject multiple join requests at once.

1
await teamsSystem.RejectJoinRequestsAsync("<teamId>", new[] { "<userId1>", "<userId2>" });

Promote team members #

Promote team members if the user has sufficient privileges.

1
await teamsSystem.PromoteUsersAsync("<teamId>", new[] { "<userId1>", "<userId2>" });

Leave team #

Leave a team for the user either by passing the team id.

1
await teamsSystem.LeaveTeamAsync("<teamId>");

Or by passing a team object.

1
await teamsSystem.LeaveTeamAsync(team);

Delete team #

Delete a team, providing the user has sufficient priviledges.

1
await teamsSystem.DeleteTeamAsync("<teamId>");

Send chat message #

Send a chat message to the user’s team.

1
var messageAck = await teamsSystem.SendChatMessageAsync("<teamId>", "<contentJson>");
Preview
The features described below are in preview at the moment.

Team Achievements #

The Team Achievements API enables teams to work together toward shared goals and unlock rewards through collective effort.

Function Reference

FunctionDescription
GetAchievementsAsyncGets all available achievements and their current progress for the team
UpdateAchievementsAsyncSubmits progress updates for multiple achievements
ClaimAchievementsAsyncClaims completed achievements to receive rewards (admins only)

The Achievement object #

AttributeTypeDefinition
IdstringUnique identifier for this achievement
NamestringDisplay name of the achievement (may be an i18n code)
DescriptionstringDescriptive text explaining the achievement goal (may be an i18n code)
CategorystringCategory grouping for organizing achievements
CountlongCurrent progress toward completion
MaxCountlongTarget value required for completion
ClaimTimeSeclongUnix timestamp when achievement reward was claimed, 0 if not claimed
TotalClaimTimeSeclongUnix timestamp when total achievement reward was claimed, 0 if not claimed
CurrentTimeSeclongUnix timestamp for the current server time
ExpireTimeSeclongUnix timestamp when achievement expires, 0 if it does not expire
ResetTimeSeclongUnix timestamp when achievement will reset
StartTimeSeclongUnix timestamp when achievement becomes available, 0 if immediately available
EndTimeSeclongUnix timestamp when achievement stops accepting updates, 0 if it does not end
PreconditionIdsstring[]Array of achievement IDs that must be completed before this one becomes available
AvailableRewardsAvailableRewardsPotential rewards and their probabilities for completion
RewardRewardReward received after claiming, null if not claimed
AvailableTotalRewardAvailableRewardsPotential rewards for total completion (including sub-achievements)
TotalRewardRewardReward received for total completion, null if not claimed
SubAchievementsMap<string, SubAchievement>Collection of sub-achievements within this achievement
AdditionalPropertiesMap<string, string>Custom metadata and configuration properties
AutoClaimboolWhether the achievement reward is automatically given upon completion
AutoClaimTotalboolWhether the total reward is automatically given upon completing all sub-achievements
AutoResetboolWhether the achievement automatically resets after completion

Get team achievements #

1
GetAchievementsAsync()

Retrieves all available achievements and their current progress for the team.

Results

  • IAchievementList: Complete collection of team achievements with progress data

Permissions

  • Requires active team membership (member or admin)

Example

1
2
3
4
5
6
7
8
var achievementList = await teamsSystem.GetAchievementsAsync();

foreach (var achievement in achievementList.Achievements)
{
    Debug.Log($"Achievement: {achievement.Id}");
    Debug.Log($"Progress: {achievement.Progress}/{achievement.Count}");
    Debug.Log($"Completed: {achievement.ClaimTimestamp > 0}");
}

Update team achievements #

1
UpdateAchievementsAsync(string[] achievementIds, long progressIncrement)

Submits progress updates for multiple achievements simultaneously.

Parameters

  • achievementIds (string[], required): Array of achievement identifiers to update
    • Constraints: Each ID must match a configured team achievement
  • progressIncrement (long, required): Amount to add to current progress
    • Behavior: Negative values reduce progress, cannot go below 0

Results

  • IAchievementsUpdateAck: Updated achievement data reflecting new progress values

Permissions

  • Requires active team membership (member or admin)

Implementation Notes

  • Progress updates are applied atomically across all specified achievements
  • Achievements with auto-claim enabled are automatically claimed when completed
  • Recurring achievements reset progress after completion
  • Updates are ignored for already-completed achievements unless they support multiple completions

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var achievementIds = new string[] { "monthly_pvp_wins", "weekly_dungeons", "daily_logins" };
var progressIncrement = 1;

var achievementsUpdate = await teamsSystem.UpdateAchievementsAsync(achievementIds, progressIncrement);

foreach (var achievement in achievementsUpdate.Achievements)
{
    Debug.Log($"Updated {achievement.Id}: {achievement.Progress}/{achievement.Count}");

    if (achievement.Progress >= achievement.Count)
    {
        Debug.Log($"{achievement.Id} is ready to claim!");
    }
}

Claim team achievements #

1
ClaimAchievementsAsync(string[] achievementIds)

Claims completed achievements to receive configured rewards.

Parameters

  • achievementIds (string[], required): Array of achievement identifiers to claim
    • Constraints: Each ID must match a completed team achievement

Results

  • IAchievementsUpdateAck: Updated achievement data with claim timestamps and reward information

Permissions

  • Requires admin or superadmin role within the team
  • Regular members cannot claim achievements

Implementation Notes

  • Achievements must be completed (progress >= count) before claiming
  • Each achievement can only be claimed once per completion cycle
  • Recurring achievements become available for new progress after claiming
  • Operation is idempotent for already-claimed achievements

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var achievementIds = new string[] { "monthly_challenge_complete", "pvp_master" };

var achievementsUpdate = await teamsSystem.ClaimAchievementsAsync(achievementIds);

foreach (var achievement in achievementsUpdate.Achievements)
{
    if (achievement.ClaimTimestamp > 0)
    {
        Debug.Log($"Successfully claimed {achievement.Id}!");
    }
}

Team Event Leaderboards #

The Team Event Leaderboards API enables teams to compete in time-limited events with tier-based matchmaking and cohort competition.

Function Reference

FunctionDescription
ListEventLeaderboardsAsyncLists all available event leaderboards for the team
GetEventLeaderboardAsyncGets detailed information about a specific event leaderboard
RollEventLeaderboardAsyncEnrolls the team into a cohort for an event with tier-based matchmaking
UpdateEventLeaderboardAsyncSubmits individual member scores that contribute to the team’s total
ClaimEventLeaderboardRewardAsyncClaims rewards after an event ends based on final team ranking

The TeamEventLeaderboard object #

AttributeTypeDefinition
IdstringEvent leaderboard identifier
NamestringDisplay name of the event leaderboard (may be an i18n code)
DescriptionstringDescriptive text explaining the event (may be an i18n code)
CategorystringCategory grouping for filtering events
AscendingboolScore ordering direction (true = lowest first, false = highest first)
OperatorstringScore submission operator (INCREMENT, DECREMENT, SET, BEST)
TierintCurrent tier level for matchmaking (0 = lowest tier)
StartTimeSeclongUnix timestamp when the current event iteration started
EndTimeSeclongUnix timestamp when the current event iteration ends
ExpiryTimeSeclongUnix timestamp when rewards expire and new iteration begins
AvailableRewardsAvailableRewardsPotential rewards and their probabilities for current rank
RewardTiersMap<int, EventLeaderboardRewardTiers>Reward structure for each tier of this event leaderboard
ChangeZonesMap<int, EventLeaderboardChangeZone>Per-tier promotion/demotion zones, if configured
ClaimTimeSeclongUnix timestamp when rewards were claimed, 0 if not claimed
RewardRewardReward received after claiming, null if not claimed
AdditionalPropertiesMap<string, string>Custom metadata and configuration properties
CountlongCurrent participant count in the cohort
MaxCountlongMaximum participant count for the cohort
MaxNumScorelongMaximum number of score submissions per participant
ScoresTeamEventLeaderboardScore[]Array of all team scores in the cohort
IsActiveboolWhether new scores can be submitted to this event
CanClaimboolWhether rewards are available to claim
CanRollboolWhether the team can enroll in a new iteration
MatchmakerPropertiesStructExtra matchmaker properties for this cohort
CurrentTimeSeclongUnix timestamp for the current server time
CohortIdstringID of the cohort this team is competing in, empty if not enrolled
BackingIdstringBacking ID for underlying score tracking
ContributionsTeamEventLeaderboardContribution[]Array of individual member contributions to team score

TeamEventLeaderboardScore #

AttributeTypeDefinition
IdstringTeam ID for this leaderboard participant
NamestringTeam name
AvatarUrlstringTeam avatar URL
CreateTimeSeclongUnix timestamp when team first joined this event
UpdateTimeSeclongUnix timestamp when team last submitted a score
RanklongPosition in cohort rankings (1 = first place)
ScorelongTeam’s total score
SubscorelongTeam’s subscore for tiebreaking
NumScoreslongNumber of score submissions made by this team
MetadatastringJSON metadata from team’s last score submission

TeamEventLeaderboardContribution #

AttributeTypeDefinition
IdstringUser ID of contributing team member
UsernamestringUsername of contributing member
DisplayNamestringDisplay name of contributing member
AvatarUrlstringAvatar URL of contributing member
CreateTimeSeclongUnix timestamp when member first contributed
UpdateTimeSeclongUnix timestamp of member’s last contribution
ScorelongMember’s aggregate contribution to team score
SubscorelongMember’s aggregate contribution to team subscore
NumScoreslongNumber of score submissions made by this member
MetadatastringJSON metadata from member’s last score submission

List team event leaderboards #

1
ListEventLeaderboardsAsync()

Retrieves all available event leaderboards for the team, including both active and enrollable events.

Results

  • ITeamEventLeaderboards: Collection containing all event leaderboards

Permissions

  • Requires active team membership (member or admin)

Example

1
2
3
4
5
6
7
var eventLeaderboards = await teamsSystem.ListEventLeaderboardsAsync();

foreach (var leaderboard in eventLeaderboards.EventLeaderboards)
{
    Debug.Log($"Event: {leaderboard.Id} - Active: {leaderboard.IsActive}");
    Debug.Log($"Team Rank: {leaderboard.Rank} - Can Claim: {leaderboard.CanClaim}");
}

Get team event leaderboard #

1
GetEventLeaderboardAsync(string leaderboardId)

Retrieves detailed information about a specific event leaderboard including team standings, scores, and member contributions.

Parameters

  • leaderboardId (string, required): Event leaderboard identifier
    • Constraints: Must match a configured event leaderboard ID

Results

  • ITeamEventLeaderboard: Complete event leaderboard data with scores and contributions

Permissions

  • Requires active team membership (member or admin)

Implementation Notes

  • May fail if the event has reached maximum participants or has other enrollment constraints

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var leaderboardId = "weekly_tournament";
var eventLeaderboard = await teamsSystem.GetEventLeaderboardAsync(leaderboardId);

Debug.Log($"Team Rank: {eventLeaderboard.Rank}");
Debug.Log($"Team Score: {eventLeaderboard.Score}");
Debug.Log($"Can Claim: {eventLeaderboard.CanClaim}");

// View individual member contributions
foreach (var contribution in eventLeaderboard.Contributions)
{
    Debug.Log($"{contribution.Username}: {contribution.Score} points");
}

Roll into team event leaderboard #

1
RollEventLeaderboardAsync(string leaderboardId)

Enrolls the team into a cohort for an event that has not yet started, with automatic tier-based matchmaking.

Parameters

  • leaderboardId (string, required): Event leaderboard identifier
    • Constraints: Must match a configured event leaderboard ID

Results

  • ITeamEventLeaderboard: Event leaderboard data after enrollment

Permissions

  • Requires active team membership (member or admin)

Implementation Notes

  • Teams are automatically matched with others in the same tier
  • Cohort assignment is permanent for the duration of the event
  • Cannot re-roll while an active event is in progress
  • Tier progression is based on previous event performance

Example

1
2
3
4
5
6
var leaderboardId = "weekly_tournament";
var eventLeaderboard = await teamsSystem.RollEventLeaderboardAsync(leaderboardId);

Debug.Log($"Enrolled in cohort: {eventLeaderboard.CohortId}");
Debug.Log($"Current tier: {eventLeaderboard.Tier}");
Debug.Log($"Competing against {eventLeaderboard.Scores.Count} teams");

Update team event leaderboard score #

1
UpdateEventLeaderboardAsync(string leaderboardId, long score, long subscore = 0, Dictionary<string, string> metadata = default)

Submits individual member scores that contribute to the team’s total score based on the event’s operator configuration. (See: Score Operators)

Parameters

  • leaderboardId (string, required): Event leaderboard identifier
    • Constraints: Must match a configured event leaderboard ID
  • score (long, required): Primary score to submit. Accepts negative values, but beware of interactions with the event leaderboard’s configured operator e.g., a negative score combined with the DECR operator will increase the score.
  • subscore (long, optional): Secondary score for tiebreaking
    • Default behavior: Uses 0 if not provided
  • metadata (Dictionary<string, string>, optional): Custom data associated with this submission
    • Default behavior: Empty metadata if not provided; null dictionary becomes empty JSON object
    • Constraints: Values must be JSON-serializable strings

Results

  • ITeamEventLeaderboard: Updated event leaderboard data with new rankings

Permissions

  • Requires active team membership (member or admin)

Implementation Notes

  • Scores are aggregated according to the event’s operator (SUM, MAX, MIN, etc.)
  • Team must be enrolled in the event before submitting scores
  • Submissions are only accepted during the active event window
  • Individual contributions are tracked separately from team totals
  • Teams may only submit up to MaxNumScore as defined in the config

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var leaderboardId = "weekly_tournament";
var score = 1500;
var subscore = 50;
var metadata = new Dictionary<string, string>
{
    {"mission_type", "daily_challenge"},
    {"difficulty", "hard"},
    {"completion_time", "120"}
};

var eventLeaderboard = await teamsSystem.UpdateEventLeaderboardAsync(
    leaderboardId, score, subscore, metadata);

Debug.Log($"Updated score. New team total: {eventLeaderboard.Score}");
Debug.Log($"Team rank: {eventLeaderboard.Rank}");

Claim team event leaderboard rewards #

1
ClaimEventLeaderboardRewardAsync(string leaderboardId)

Claims rewards after an event ends based on the team’s final ranking and tier placement.

Parameters

  • leaderboardId (string, required): Event leaderboard identifier
    • Constraints: Must match a configured event leaderboard ID

Results

  • ITeamEventLeaderboard: Event leaderboard data with claimed reward information

Permissions

  • Requires active team membership (member or admin)

Implementation Notes

  • Rewards can only be claimed after the event has ended but before the reward expires
  • Rewards are distributed based on final rank within the cohort
  • Each event can only be claimed once per team
  • Operation is idempotent - multiple claims return the same result

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var leaderboardId = "weekly_tournament";
var eventLeaderboard = await teamsSystem.ClaimEventLeaderboardRewardAsync(leaderboardId);

Debug.Log($"Rewards claimed for rank {eventLeaderboard.Rank}");
Debug.Log($"Claim time: {eventLeaderboard.ClaimTimeSec}");

// Access reward details
if (eventLeaderboard.Reward != null)
{
    foreach (var currency in eventLeaderboard.Reward.Currencies)
    {
        Debug.Log($"Earned {currency.Value} {currency.Key}");
    }
}

Team Inventory #

The Team Inventory API enables teams to manage shared items, view item properties, consume items for rewards, and grant items to the group inventory.

Function Reference

FunctionDescription
GetItemCodexAsyncGets all available item definitions and configurations
GetItemsAsyncGets the team’s current inventory with item instances
ConsumeItemsAsyncConsumes items from inventory and receives configured rewards
GrantItemsAsyncAdds items to the team’s inventory
UpdateItemsAsyncUpdates custom properties of existing inventory items

The Inventory object #

AttributeTypeDefinition
ItemsMap<string, InventoryItem>Collection of inventory items keyed by instance ID

InventoryItem #

AttributeTypeDefinition
IdstringUnique identifier for this item type
InstanceIdstringUnique identifier for this specific item instance
NamestringDisplay name of the item (may be an i18n code)
DescriptionstringDescriptive text explaining the item (may be an i18n code)
CategorystringCategory grouping for organizing items
ItemSetsstring[]Array of item set identifiers this item belongs to
CountlongCurrent quantity of this item in the inventory
MaxCountlongMaximum quantity that can be owned for this item type
StackableboolWhether multiple instances can be combined into a single stack
ConsumableboolWhether this item can be consumed for rewards
ConsumeAvailableRewardsAvailableRewardsPotential rewards and probabilities when consuming this item
StringPropertiesMap<string, string>Custom text-based properties for this item instance
NumericPropertiesMap<string, double>Custom numeric properties for this item instance
OwnedTimeSeclongUnix timestamp when the team acquired this item
UpdateTimeSeclongUnix timestamp when this item was last modified

Get team item codex #

1
GetItemCodexAsync()

Retrieves the item catalog/reference for a team i.e., a list of all possible items that could exist in the team’s inventory system, not the items the team actually owns.

Results

  • IInventoryList: Complete catalog of item definitions and metadata

Permissions

  • Requires active team membership (member or admin)

Example

1
2
3
4
5
6
7
8
var itemCodex = await teamsSystem.GetItemCodexAsync();

foreach (var item in itemCodex.Items)
{
    Debug.Log($"Item: {item.Value.Name} - Category: {item.Value.Category}");
    Debug.Log($"Stackable: {item.Value.Stackable} - Consumable: {item.Value.Consumable}");
    Debug.Log($"Max Count: {item.Value.MaxCount}");
}

Get team items #

1
GetItemsAsync()

Retrieves the team’s current inventory with all owned item instances.

Results

  • IInventoryList: Team’s inventory containing owned items with quantities and properties

Permissions

  • Requires active team membership (member or admin)

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var teamInventory = await teamsSystem.GetItemsAsync();

foreach (var item in teamInventory.Items)
{
    Debug.Log($"Owned: {item.Value.Name} x{item.Value.Count}");
    Debug.Log($"Instance ID: {item.Value.InstanceId}");
    Debug.Log($"Acquired: {item.Value.OwnedTimeSec}");

    // Check custom properties
    foreach (var prop in item.Value.StringProperties)
    {
        Debug.Log($"Property {prop.Key}: {prop.Value}");
    }
}

Consume team items #

1
ConsumeItemsAsync(Dictionary<string, long> itemsToConsume, Dictionary<string, long> instancesToConsume, bool overConsume)

Consumes items from the team inventory and receives configured rewards.

Parameters

  • itemsToConsume (Dictionary<string, long>, required): Map of item IDs to quantities to consume
    • Constraints: Item IDs must exist in team inventory with sufficient quantities
  • instancesToConsume (Dictionary<string, long>, required): Map of instance IDs to quantities to consume
    • Constraints: Instance IDs must exist in team inventory with sufficient quantities
  • overConsume (bool, required): Whether to allow consuming more items than available
    • Behavior: If true, consumes all available items even if less than requested

Results

  • IInventoryConsumeRewards: Rewards received from consumption and updated inventory state

Permissions

  • Requires admin role within the team
  • Regular members cannot consume team inventory items

Implementation Notes

  • Items must be marked as consumable in their configuration
  • Consumption is atomic: either all specified items are consumed or none are
  • Rewards are determined by item configuration and applied immediately
  • Non-consumable items cannot be consumed regardless of parameters

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
var itemsToConsume = new Dictionary<string, long>
{
    {"health_potion", 2},
    {"mana_crystal", 1}
};

var instancesToConsume = new Dictionary<string, long>
{
    {"unique_sword_instance_123", 1}
};

var rewards = await teamsSystem.ConsumeItemsAsync(itemsToConsume, instancesToConsume, false);

Debug.Log($"Consumed items successfully");
foreach (var currency in rewards.Reward.Currencies)
{
    Debug.Log($"Received {currency.Value} {currency.Key}");
}

Grant team items #

1
GrantItemsAsync(Dictionary<string, long> itemsToGrant)

Adds items to the team’s shared inventory.

Parameters

  • itemsToGrant (Dictionary<string, long>, required): Map of item IDs to quantities to grant
    • Constraints: Item IDs must be configured in the team inventory system
    • Behavior: Respects maximum count limits and stacking rules per item

Results

  • IInventoryUpdateAck: Confirmation of granted items and updated inventory state

Permissions

  • Requires admin role within the team
  • Regular members cannot grant items to team inventory

Implementation Notes

  • Items are subject to maximum count limits defined in configuration
  • Stackable items will be combined with existing instances when possible
  • Non-stackable items create individual instances for each quantity
  • Granting beyond maximum limits will result in partial grants up to the limit

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var itemsToGrant = new Dictionary<string, long>
{
    {"team_banner", 1},
    {"upgrade_material", 50},
    {"legendary_weapon", 1}
};

var updateAck = await teamsSystem.GrantItemsAsync(itemsToGrant);

Debug.Log($"Items granted successfully");
foreach (var item in updateAck.Items)
{
    Debug.Log($"Granted: {item.Value.Name} x{item.Value.Count}");
}

Update team item properties #

1
UpdateItemsAsync(Dictionary<string, UpdateInventoryItemProperties> itemsToUpdate)

Updates custom properties of existing inventory items.

Parameters

  • itemsToUpdate (Dictionary<string, UpdateInventoryItemProperties>, required): Map of instance IDs to property updates
    • Constraints: Instance IDs must exist in team inventory
    • Behavior: Only updates specified properties, leaves others unchanged

UpdateInventoryItemProperties Properties

  • StringProperties (Dictionary<string, string>, optional): Text-based properties to update
  • NumericProperties (Dictionary<string, double>, optional): Numeric properties to update

Results

  • IInventoryUpdateAck: Confirmation of updates and current item state

Permissions

  • Requires admin role within the team
  • Regular members cannot update team inventory item properties

Implementation Notes

  • Only custom properties can be updated, not core item attributes like count or category
  • Property updates are merged with existing properties
  • Setting a property value to null or empty removes that property
  • Property names and value types must match configuration constraints

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var itemUpdates = new Dictionary<string, UpdateInventoryItemProperties>
{
    ["sword_instance_456"] = new UpdateInventoryItemProperties
    {
        StringProperties = new Dictionary<string, string>
        {
            {"enchantment", "fire_damage"},
            {"crafted_by", "master_smith"}
        },
        NumericProperties = new Dictionary<string, double>
        {
            {"damage_bonus", 15.5},
            {"durability", 98.2}
        }
    }
};

var updateAck = await teamsSystem.UpdateItemsAsync(itemUpdates);

Debug.Log($"Item properties updated successfully");

Team Mailbox #

The Team Mailbox API manages deferred reward delivery for teams, providing secure storage and controlled claiming of rewards sent to the team’s shared mailbox.

Function Reference

FunctionDescription
ListMailboxAsyncRetrieves paginated list of mailbox entries for the team
ClaimMailboxRewardAsyncClaims rewards from a specific mailbox entry and optionally deletes it
DeleteMailboxAsyncRemoves one or more mailbox entries without claiming rewards

The MailboxList object #

AttributeTypeDefinition
EntriesMailboxEntry[]Array of mailbox entries for this team
CursorstringPagination cursor to fetch more results, empty if no more

MailboxEntry #

AttributeTypeDefinition
IdstringUnique identifier for this mailbox entry
RewardRewardReward object containing currencies, items, and other assets
CreateTimeSeclongUnix timestamp when this entry was created
UpdateTimeSeclongUnix timestamp when this entry was last modified
ExpiryTimeSeclongUnix timestamp when this entry expires and becomes invalid
ClaimTimeSeclongUnix timestamp when this entry was claimed, 0 if unclaimed
CanClaimboolWhether this entry’s reward can currently be claimed

List team mailbox entries #

1
ListMailboxAsync(int limit = 100)

Retrieves a paginated list of mailbox entries for the team, including both claimed and unclaimed rewards.

Parameters

  • limit (int, optional): Maximum number of entries to return per page
    • Default behavior: Returns up to 100 entries if not specified
    • Constraints: Must be between 1 and 100; values outside this range are clamped

Results

  • IMailboxList: Paginated collection of mailbox entries with cursor for additional pages

Permissions

  • Requires active team membership (member or admin)
  • Cannot access mailbox from teams where user is banned or has pending membership

Implementation Notes

  • Results are ordered by creation time (newest first)
  • Expired entries are automatically filtered from results
  • Pagination cursor enables efficient traversal of large mailbox collections

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var mailboxList = await teamsSystem.ListMailboxAsync(50);

foreach (var entry in mailboxList.Entries)
{
    Debug.Log($"Entry {entry.Id}: Can Claim = {entry.CanClaim}");

    if (entry.Reward?.Currencies != null)
    {
        foreach (var currency in entry.Reward.Currencies)
        {
            Debug.Log($"  Reward: {currency.Value} {currency.Key}");
        }
    }
}

// Handle pagination if more entries exist
if (!string.IsNullOrEmpty(mailboxList.Cursor))
{
    Debug.Log("More entries available - use cursor for next page");
}

Claim team mailbox entry #

1
ClaimMailboxRewardAsync(string mailboxId, bool deleteAfterClaim = true)

Claims the reward from a specific mailbox entry and optionally removes the entry from the mailbox after successful claiming.

Parameters

  • mailboxId (string, required): Unique identifier of the mailbox entry to claim
    • Constraints: Must be a valid entry ID that exists in the team’s mailbox
  • deleteAfterClaim (bool, optional): Whether to remove the entry after claiming
    • Default behavior: Entry is deleted after claiming if not specified
    • Use case: Set to false to keep entry for record-keeping or reference

Results

  • IMailboxEntry: Updated mailbox entry with claim timestamp and reward details

Permissions

  • Requires active team membership (member or admin)
  • All team members can claim rewards from the shared mailbox

Implementation Notes

  • Entry must be claimable (CanClaim = true) and not expired
  • Rewards are added directly to team resources (wallet, inventory, etc.)
  • Operation is idempotent - claiming the same entry multiple times returns the same result
  • Claimed entries cannot be unclaimed once processed

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var entryId = "mailbox_entry_123";
var claimedEntry = await teamsSystem.ClaimMailboxRewardAsync(entryId, deleteAfterClaim: true);

Debug.Log($"Claimed reward at: {claimedEntry.ClaimTimeSec}");

// Check what rewards were received
if (claimedEntry.Reward?.Currencies != null)
{
    foreach (var currency in claimedEntry.Reward.Currencies)
    {
        Debug.Log($"Received {currency.Value} {currency.Key}");
    }
}

// Entry is now deleted from mailbox (if deleteAfterClaim was true)

Delete team mailbox entries #

1
DeleteMailboxAsync(string[] entryIds)

Removes one or more mailbox entries without claiming their rewards, useful for clearing expired or unwanted entries.

Parameters

  • entryIds (string[], required): Array of mailbox entry identifiers to delete
    • Constraints: All entry IDs must exist in the team’s mailbox
    • Behavior: Non-existent entries are silently ignored without causing errors

Results

  • Task: Completion task with no return value

Permissions

  • Requires admin or superadmin role within the team
  • Regular members cannot delete mailbox entries

Implementation Notes

  • Deleted entries and their rewards are permanently lost and cannot be recovered
  • Operation is atomic: either all specified entries are deleted or none are
  • Useful for mailbox maintenance and removing expired promotional rewards

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var entriesToDelete = new string[]
{
    "expired_entry_456",
    "promotional_reward_789",
    "outdated_bonus_012"
};

await teamsSystem.DeleteMailboxAsync(entriesToDelete);

Debug.Log($"Deleted {entriesToDelete.Length} mailbox entries");

// Verify deletion by listing mailbox again
var updatedMailbox = await teamsSystem.ListMailboxAsync();
Debug.Log($"Remaining entries: {updatedMailbox.Entries.Count}");

Team Stats #

The Team Stats API provides tracking and managing public and private stats for teams.

Function Reference

FunctionDescription
GetStatsAsyncGets the current team’s public and private statistics
UpdateStatsAsyncUpdates public and/or private statistics with various operations

The TeamStat object #

AttributeTypeDefinition
NamestringThe unique identifier for this stat
PublicboolIndicates whether this stat is publicly visible (true) or private (false)
UpdateTimeSeclongUnix timestamp when this stat was last modified
ValuelongCurrent value of the stat
CountlongNumber of values that have been submitted for this stat
TotallongTotal of all submitted values for this stat
MinlongSmallest value that has ever been submitted for this stat
MaxlongLargest value that has ever been submitted for this stat
FirstlongFirst value that was submitted for this stat
LastlongLatest value that was submitted for this stat
AdditionalPropertiesStructCustom metadata and configuration properties associated with this stat

Get team stats #

1
GetStatsAsync()

Retrieves the current team’s complete stats data, including both public and private stats.

Result

  • Returns IStatList: Complete stats object containing public and private stat collections
  • Updates local PrivateStats and PublicStats properties
  • Notifies observers

Permissions

  • Requires active team membership (member or admin)
  • Cannot retrieve stats from teams where user is banned or has pending membership

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var statList = await teamsSystem.GetStatsAsync();

// Access via properties after refresh
foreach (var stat in teamsSystem.PrivateStats)
{
    Debug.Log($"Private Stat - {stat.Key}: {stat.Value.CurrentValue}");
}

foreach (var stat in teamsSystem.PublicStats)
{
    Debug.Log($"Public Stat - {stat.Key}: {stat.Value.CurrentValue}");
}

// Direct access to returned object
Debug.Log($"Team Level: {statList.Public["team_level"].CurrentValue}");

Update team stats #

1
UpdateStatsAsync(List<UpdateStat>? privateStats, List<UpdateStat>? publicStats)

Modifies team stats using various mathematical operations, supporting both individual and batch updates.

Parameters

  • privateStats (List<UpdateStat>, optional): Collection of private stat modifications
    • Default behavior: No private stats updated if null or empty
  • publicStats (List<UpdateStat>, optional): Collection of public stat modifications
    • Default behavior: No public stats updated if null or empty

UpdateStat Properties

  • Name (string, required): Stat identifier matching configuration
    • Constraints: Must exist in team stats configuration; alphanumeric and underscore only. Case-sensitive
  • Value (long, required): Numeric value for the operation
  • Operator (StatOperator, required): Mathematical operation to perform

Results

  • Updates local PrivateStats and PublicStats properties
  • Notifies observers
  • Generates publisher events for cross-system integrations

Permissions

  • Requires admin or superadmin role within the team
  • Regular members cannot directly update team statistics

Implementation Notes

  • All stat names must be pre-configured in the team configuration
  • Operations are atomic: either all updates succeed or all fail
  • Concurrent updates by different admins may require retry logic
  • Stat values are clamped to int64 range to prevent overflow

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var privateStatsToUpdate = new List<UpdateStat>
{
    new UpdateStat { Name = "experience_points", Value = 100, Operator = StatOperator.DELTA },
    new UpdateStat { Name = "team_level", Value = 5, Operator = StatOperator.MAX }
};

var publicStatsToUpdate = new List<UpdateStat>
{
    new UpdateStat { Name = "wins", Value = 1, Operator = StatOperator.DELTA },
    new UpdateStat { Name = "total_score", Value = 1500, Operator = StatOperator.MAX }
};

await teamsSystem.UpdateStatsAsync(privateStatsToUpdate, publicStatsToUpdate);

Stat Update Operators

OperationBehaviorConsiderations
SETOverwrites current valueValues exceeding int64 range are clamped, null treated as 0
DELTAAdds/subtracts from currentNegative results allowed; overflow protection applied, null treated as 0
MINUpdates only if new < currentWorks with negative values
MAXUpdates only if new > currentWorks with negative values

Team Store #

The Team Store API enables teams to browse and purchase items using shared team currencies and view active promotional modifiers.

Function Reference

FunctionDescription
GetStoreAsyncGets available store items and active promotional modifiers for the team

The TeamStore object #

AttributeTypeDefinition
StoreItemsTeamStoreItem[]Array of items available for purchase in the team store
ActiveRewardModifiersActiveRewardModifier[]Array of currently active promotional modifiers affecting rewards
CurrentTimeSeclongUnix timestamp for the current server time

TeamStoreItem #

AttributeTypeDefinition
IdstringUnique identifier for this store item
NamestringDisplay name of the store item (may be an i18n code)
DescriptionstringDescriptive text explaining the item (may be an i18n code)
CategorystringCategory grouping for organizing store items
CostTeamStoreItemCostCurrency requirements and pricing information for this item
AvailableRewardsAvailableRewardsPotential rewards and their probabilities when purchasing this item
AdditionalPropertiesMap<string, string>Custom metadata and configuration properties
UnavailableboolWhether the item is visible but cannot be purchased

Get team store #

1
GetStoreAsync()

Retrieves available store items and active promotional modifiers for the team.

Results

  • ITeamStore: Complete store data including items and active promotions

Permissions

  • Requires active team membership (member or admin)

Implementation Notes

  • Store items may have availability restrictions based on team level or achievements
  • Active reward modifiers automatically apply to relevant purchases
  • Item prices and availability can change based on server-side configuration updates

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var teamStore = await teamsSystem.GetStoreAsync();

// Browse available items
foreach (var item in teamStore.StoreItems)
{
    Debug.Log($"Item: {item.Id} - Available: {!item.Unavailable}");
    Debug.Log($"Name: {item.Name} - Category: {item.Category}");

    if (item.Cost != null)
    {
        Debug.Log($"Cost: {item.Cost} team currency");
    }

    if (item.Unavailable)
    {
        Debug.Log($"Item {item.Id} is currently unavailable for purchase");
    }
}

// Check active promotions
foreach (var modifier in teamStore.ActiveRewardModifiers)
{
    Debug.Log($"Active Promotion: {modifier.Id}");
    Debug.Log($"Expires: {modifier.EndTimeSec}");
}

Debug.Log($"Server time: {teamStore.CurrentTimeSec}");

Team Wallet #

The Team Wallet API manages shared currency resources for teams, enabling collective resource accumulation and administrative control over team finances.

Function Reference

FunctionDescription
GetWalletAsyncRetrieves current team wallet balances for all currencies
GrantAsyncAdds specified currency amounts to the team’s shared wallet

The TeamWallet object #

AttributeTypeDefinition
IdstringTeam identifier this wallet belongs to
CurrenciesMap<string, long>Current currency balances in the team’s shared wallet
UpdateTimeSeclongUnix timestamp when the wallet was last modified

Get team wallet #

1
GetWalletAsync()

Retrieves the current balances for all currencies in the team’s shared wallet.

Results

  • Dictionary<string, long>: Currency balances keyed by currency identifier
  • Notifies observers

Permissions

  • Requires active team membership (member or admin)

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var walletBalances = await teamsSystem.GetWalletAsync();

// Access via returned dictionary
foreach (var currency in walletBalances)
{
    Debug.Log($"Currency {currency.Key}: {currency.Value}");
}

// Access via property after refresh
Debug.Log($"Team Coins: {teamsSystem.Wallet["coins"]}");
Debug.Log($"Team Gems: {teamsSystem.Wallet["gems"]}");

Grant team currencies #

1
GrantAsync(Dictionary<string, long> currencies)

Adds the specified currency amounts to the team’s shared wallet, supporting multiple currencies in a single operation.

Parameters

  • currencies (Dictionary<string, long>, required): Currency amounts to add to the team wallet
    • Constraints: Currency identifiers must match team wallet configuration; values must be positive
    • Key format: Currency identifier strings (e.g., “coins”, “gems”, “tokens”)
    • Value format: Positive integer amounts to add

Results

  • Updates local Wallet property with new balances
  • Notifies observers
  • Generates publisher events for currency tracking

Permissions

  • Requires admin or superadmin role within the team
  • Regular members cannot directly modify team wallet

Implementation Notes

  • All currency identifiers must be pre-configured in the team wallet setup
  • Operations are atomic: either all currency grants succeed or all fail
  • Currency values are added to existing balances, not replaced
  • Negative values are not supported - use other systems for currency deduction

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var currenciesToGrant = new Dictionary<string, long>
{
    { "coins", 1000 },
    { "gems", 50 },
    { "event_tokens", 25 }
};

await teamsSystem.GrantAsync(currenciesToGrant);

// Check updated balances
Debug.Log($"New coin balance: {teamsSystem.Wallet["coins"]}");
Debug.Log($"New gem balance: {teamsSystem.Wallet["gems"]}");