Parties

Parties let friends queue together. They are optional: skip this page if your game only does solo searches. For how parties work on the platform, including team placement, see Parties; this page is the Unity side.

Parties need two things before they work:

  • Turn parties on for the game mode in the dashboard (see Game Modes).
  • Connect before you search. A party is formed over the connection, so you open it first with ConnectAsync instead of letting BeginSearchAsync open it.

Needs SDK 1.2.0

Parties arrived in version 1.2.0 of the SDK, which implements version 1.1.0 of the API Specs.

The flow

await _matchmaking.ConnectAsync("eu-west-2");      // open the connection, don't search yet
await _matchmaking.CreatePartyAsync();             // you are the leader
// ...share party.JoinCode with your friends...
await _matchmaking.BeginSearchAsync("3v3");        // leader only: queues the whole party

A friend, connected the same way, joins with the code:

await _matchmaking.ConnectAsync("eu-west-2");
await _matchmaking.JoinPartyAsync("K7M2QX");

BeginSearchAsync on a connection opened with ConnectAsync searches on that same connection, so the party stays intact.

Use the same region for everyone

Every member of a party needs a ticket for the same region. Pass the same region to ConnectAsync for the whole group, rather than leaving it to automatic selection. The region is passed to your ticket endpoint as preferredRegion.

Party methods

MethodWhoEffect
ConnectAsync(region)anyoneOpens the connection without searching. State becomes Connected.
CreatePartyAsync()anyoneCreates a party with you as leader.
JoinPartyAsync(code)anyoneJoins the party with that join code.
InviteToPartyAsync(userId)leaderInvites a connected player. They receive OnPartyInvite.
AcceptInviteAsync(partyId)inviteeJoins the inviting party.
DeclineInviteAsync(partyId)inviteeDiscards the invite. Optional: invites expire after two minutes.
LeavePartyAsync()any memberLeaves the party.
KickMemberAsync(userId)leaderRemoves a member.
PromoteLeaderAsync(userId)leaderHands leadership to another member.

Each call returns once the request is sent. The result arrives as an event: a PartyState on OnPartyUpdated, or an error on OnError. The party methods throw InvalidOperationException if there is no open connection, and ConnectAsync throws if it can't get a ticket or open the connection.

Showing the party

OnPartyUpdated always carries the full party, so render from it instead of patching your UI:

_matchmaking.OnPartyUpdated.AddListener(party =>
{
    codeLabel.text = party.JoinCode;
    memberList.text = string.Join("\n", party.Members.Select(m =>
        m.UserId == party.LeaderUserId ? m.UserId + " (leader)" : m.UserId));
    searchButton.interactable = party.PartyStatus == PartyStatus.Lobby && IsLeader(party);
});
 
_matchmaking.OnPartyLeft.AddListener(left => ShowMainMenu());

_matchmaking.Party holds the latest state, or null when you aren't in a party. Like the events, read it on Unity's main thread.

PartyState has PartyId, JoinCode, LeaderUserId, Members (each with a UserId), PartyStatus and, while a ping check is running, GameMode. PartyStatus is:

StatusMeaning
LobbyForming up. Members can join and leave.
StartingA ping-based game mode is measuring each member's latency. Membership is locked.
SearchingQueued. Membership is locked.

Knowing whether you are the leader

LeaderUserId and each member's UserId are the userId values your backend chose when it minted the tickets. The SDK doesn't see them, so to tell whether the local player leads the party, keep their userId on the client (it's usually their account ID) and compare:

bool IsLeader(PartyState party) => party.LeaderUserId == _myUserId;

Inviting a player

The leader invites by userId, and the invitee accepts with the PartyId from the invite:

await _matchmaking.InviteToPartyAsync("bob");     // leader
 
_matchmaking.OnPartyInvite.AddListener(invite =>  // bob's client
{
    ShowInvitePrompt(invite.FromUserId, accept: () =>
        _ = _matchmaking.AcceptInviteAsync(invite.PartyId));
});

The invited player must be connected, in your own tenant, and not already in a party. If the invite can't be delivered you get PARTY_INVITEE_UNAVAILABLE, which deliberately doesn't say whether the player is offline or just busy. Invites expire after two minutes.

Searching as a party

Only the leader calls BeginSearchAsync. It queues every member at once, and the other members don't call it at all. When the party is queued, every member's OnSearchStarted fires and their state becomes Searching; the SDK then sends their heartbeats for them.

_matchmaking.OnSearchStarted.AddListener(started =>
    Debug.Log($"Queued in {started.GameMode}, party {started.PartyId}"));

In a UI, enable Search and Cancel only for the leader. A member who calls BeginSearchAsync gets NOT_PARTY_LEADER, and the SDK drops back out of Searching.

  • CancelSearchAsync() from the leader stops the search for everyone.
  • If a member leaves, is kicked or disconnects mid-search, the search is cancelled for everyone. The remaining members receive OnPartySearchCancelled with a Reason of LEADER_CANCELLED, MEMBER_LEFT, MEMBER_KICKED, MEMBER_DISCONNECTED or START_FAILED.
  • While the party is Starting or Searching, nobody can join and the leader can't invite.
  • For ping-based game modes there is a short extra step first, with each member's SDK answering the ping check automatically. If a member doesn't answer within 10 seconds the party quietly returns to Lobby, so have the leader search again.

After a match

Each player receives OnMatchFound as usual, and the party returns to Lobby on the same connection, so the same group can search again. The state returns to Connected. Don't call CloseAsync() if the party should stay together: closing the connection removes the player from the party. See After a Match.

When the connection drops

A search started with BeginSearchAsync alone reconnects for you. A connection opened with ConnectAsync does not: the server removes a disconnected player from their party straight away, so there is nothing to resume. The state becomes Closed and Party becomes null. Call ConnectAsync again and rejoin with the join code or a new invite.

An idle connection can also be closed by the platform after about ten minutes. If your party sits in the lobby for long periods, expect to handle Closed and offer to rebuild it.

Errors

Party errors arrive on OnError, never close the connection, and are not terminal:

CodeMeaning
ALREADY_IN_PARTY / NOT_IN_PARTYYou tried to create or join while in a party, or act on one while in none.
PARTY_NOT_FOUNDThe join code or party doesn't exist.
PARTY_MEMBER_NOT_FOUNDThe userId isn't in your party.
PARTY_FULLThe party is at the game mode's party size limit.
PARTY_SEARCHINGThe party is searching or starting, so it can't change.
NOT_PARTY_LEADEROnly the leader can do that.
PARTIES_NOT_ENABLEDParties are off for this game mode.
PARTY_TOO_LARGEThe party is bigger than the game mode allows.
PARTY_MEMBER_ATTRIBUTE_MISSINGA member's ticket lacks an attribute the game mode needs. Details names the member and attribute.
PARTY_CHANGEDThe party changed while the request ran. Retry.
PARTY_INVITEE_UNAVAILABLEThe invite couldn't be delivered.
PARTY_INVITE_NOT_FOUNDThe invite expired or doesn't exist.

Each has a matching PairiquiumErrorCode value, such as PairiquiumErrorCode.NotPartyLeader.

A worked example

The Arena Duel sample has a party panel: create a party, join by code, invite a player, and search together. See Samples & Troubleshooting.

Next

See what the SDK does for you without any code: Automatic Behaviour.