Client SDK

Unity SDK.

A small, hand-written Unity client for the matchmaking API, with no generated boilerplate. Every call is a coroutine over UnityWebRequest that reports an ApiResult<T> through a callback. Drop the client into a scene, point a config asset at your server, and call the queue / match / player / SSE surface.

This is the SDK-specific setup. The endpoint-level reference (every route, request shape and response) lives in the API reference.

Requirements

  • Unity 2021.3 LTS or newer (2022 / Unity 6 are fine).
  • The Newtonsoft Json package (com.unity.nuget.newtonsoft-json), an SDK dependency you install separately.

Install

Grab MatchKit.Matchmaking.unitypackage (the classes and editor tools, no netcode) from the dashboard, then import it one of two ways:

  • .unitypackage: double-click it, or Assets ▸ Import Package ▸ Custom Package…, to drop the SDK under Assets/MatchKit.Matchmaking.
  • UPM package: Package Manager ▸ + ▸ Add package from disk… and pick its package.json.
Worth knowing

Install the Newtonsoft Json package first: Package Manager ▸ + ▸ Add package by name… com.unity.nuget.newtonsoft-json. The SDK won't compile without it.

Setup

  1. Open Tools ▸ MatchKit Matchmaking ▸ Setup.
  2. Click Create Config Asset…, then enter your Base URL and API Key and Test Connection.
  3. Add a Matchmaking Client component to a GameObject and drag the config asset onto it.

The config is a ScriptableObject, so you can also create it via Assets ▸ Create ▸ MatchKit ▸ Matchmaking Config and edit it in its custom inspector.

Usage

Inspect IsSuccess, then read Data on success or Error / NetworkError on failure. Lifetime stats are maintained server-side, so read them with GetPlayer(id) or listen for the match-ended SSE event.

Matchmaking.cs
using MatchKit.Matchmaking;
using UnityEngine;

public class MatchmakingDemo : MonoBehaviour
{
    // Add a MatchmakingClient component and point it at a MatchmakingConfig asset.
    [SerializeField] private MatchmakingClient matchmaking;
    private SseConnection _sse;

    void Start()
    {
        // externalId is your game's own stable user id (create + update key off it).
        var request = new PlayerRequest {
            externalId = "user-42",
            username = "ace",
            region = "eu",
            matchmakingMode = MatchmakingMode.MMR,
            ratingMode = RatingMode.TS,
        };

        matchmaking.CreatePlayer(request, created => {
            if (!created.IsSuccess) { Debug.LogError(created); return; }
            long playerId = created.Data.id;

            // Server pushes arrive over SSE: "queue-update" as a match forms,
            // "match-ended" carrying the player's fresh stats afterwards.
            _sse = matchmaking.Subscribe(playerId);
            _sse.OnEvent += (name, json) => Debug.Log($"{name}: {json}");

            // Join: region, modes and rating are resolved server-side from the
            // stored player; the client never sends a score.
            matchmaking.JoinQueue(playerId, gameMode: "ranked", teamSize: 5, r => Debug.Log(r));
        });
    }

    void OnDestroy() => _sse?.Close();
}

Handing off to Mirror

MatchKit ends at a matchId and hands the roster back; your netcode takes it from there (the full picture is in Where MatchKit fits). A demo package ships that handoff for Mirror: import the SDK plus the Mirror package and add MATCHKIT_MIRROR under Project Settings ▸ Player ▸ Scripting Define Symbols.

The bridge is host-authoritative. On the match-found event every client runs the same election over the roster, and the lowest playerId hosts, so exactly one calls StartHost() and the rest StartClient(), with no extra round-trip.

Matchmaking.cs
using System.Linq;
using MatchKit.Matchmaking;
using Mirror;
using Newtonsoft.Json.Linq;
using UnityEngine;

// MatchKit tells you *who* is in the match; Mirror moves the bytes between
// them. This is the entire handoff: on match-found, agree on a host and either
// StartHost() or StartClient(). Guard it behind the MATCHKIT_MIRROR define.
public class MirrorMatchHandoff : MonoBehaviour
{
    [SerializeField] private MatchmakingClient matchmaking;
    [SerializeField] private long localPlayerId;
    private SseConnection _sse;

    void Start()
    {
        // The same SSE stream the base client uses: "match-found" fires once a
        // full roster forms, carrying { matchId, teams[][] }.
        _sse = matchmaking.Subscribe(localPlayerId);
        _sse.OnEvent += OnServerEvent;
    }

    void OnServerEvent(string name, string json)
    {
        if (name != "match-found") return;

        // "teams" is every roster in stable order — two for a classic match,
        // ten for a ten-team FFA. Flatten it and you never mind the shape.
        long[] roster = JObject.Parse(json)["teams"]
            .SelectMany(team => team)
            .Select(entry => entry["playerId"].Value<long>())
            .ToArray();

        // Every client sees the identical roster, so a pure function of it
        // elects the same host with no round-trip: lowest playerId hosts.
        long hostId = roster.Min();

        if (localPlayerId == hostId)
        {
            NetworkManager.singleton.StartHost();
        }
        else
        {
            // Mirror only needs the host's address string. How you learn it is
            // your game's call: a relay, a Steam lobby, your own signalling.
            NetworkManager.singleton.networkAddress = ResolveHostAddress(hostId);
            NetworkManager.singleton.StartClient();
        }
    }

    void OnDestroy() => _sse?.Close();
}
Worth knowing

MatchKit never carries the host's network address; it isn't in the match payload. The elected host is agreed here; how a client reaches it (a relay, a Steam lobby, your own signalling) is the one piece your game still owns.

Other netcode

MatchKit is netcode-agnostic, so the REST + SSE API works with any of these today. What's not written yet is the ready-made handoff package, so these are coming soon:

  • Photon PUN 2Coming soonmatchId as the room name; Photon Cloud relays, so there's no host election.
  • Fish-NetworkingComing soonSame host-authoritative shape as Mirror (v4 API), plus Steamworks via FishySteamworks.
Need a key?

The pre-alpha is invite-only, and keys are handed out one at a time. Tell me what you're building and I'll send you one.

Request an invite