Matchmaking API

The best team
combination.
Not the least bad.

Players queue, MatchKit forms the teams, you post the result back and the ratings update. Team formation runs through an LP solver by default, so it evaluates the combinations instead of pairing players greedily down a sorted list.

Pre-alpha, and invite-only. Tell me what you're building and I'll send you a key.

Matchmaking.cs
using MatchKit.Matchmaking;
// configured once with your API key
200 OK · Joined queue
// queue-update event over SSE
match: 1042
teams: [7,4,9,2,5] vs [3,8,1,6,0]
mode: "ranked" · size: 5v5
LP solver by default, MMR and ELO if you want them
REST + Server-Sent Events
Hosted, or self-hosted with Docker Compose
Why a solver

Averages hide the game
that's already decided.

Most matchmakers balance two teams by comparing their mean rating. Here is a queue where that goes wrong. Ten players, five a side: one at 3500, nine at 1700.

Balanced on the mean
Team A: 3500, 1700, 1700, 1700, 1700
average 2060
Team B: 1700, 1700, 1700, 1700, 1700
average 1700

2060 against 1700 looks close enough, so it ships. It isn't close. One player on Team A is twice the skill of anyone he will face, and the match is decided before it loads. The mean describes the norm. It can't see the outlier.

What MatchKit does

The LP solver treats formation as an assignment problem and evaluates the combinations, rather than walking a sorted list and pairing as it goes. When a fair split exists, it finds it, not an approximation of it.

In this queue no fair split exists. The 3500 has to go somewhere.

The fairness gate

In LP mode, which is the default, MatchKit won't ship a split whose imbalance exceeds the queue's tolerance. It forms nothing and the players stay queued for a fairer match. The tolerance is per-queue, so you decide how strict “fair” is; and a wait cap force-ships the closest split once players have waited too long, so a queue like this one, where no fair split will ever exist, still resolves rather than stranding anyone. Raise the tolerance, or switch to MMR or ELO, to turn the gate off.

How it works

Three calls. Players matched.

You don't write the queue, the skill math, or the loop that scans for a viable match.

Step 01
Register a player
Create the player once. Their rating lives on the server and is updated after every match. The client never computes a score, so it can't lie about one.
matchmaking.CreatePlayer(new PlayerRequest {
  username = "ace",
  region = "eu",
  matchmakingMode = MatchmakingMode.LP,
  ratingMode = RatingMode.TS
}, created => { /* ... */ });
Step 02
Join the queue
Queues are keyed by game mode and team size. Region, rating, and modes come from the stored player, so the join call is three fields.
matchmaking.JoinQueue(
  playerId,
  gameMode: "ranked",
  teamSize: 5
);
Step 03
Send the result back
Post the winning team and the per-player stats. Ratings update, match history is written, and the next match the queue forms is a better one.
matchmaking.EndMatch(matchId, new EndMatchRequest {
  winningTeamId = teamA,
  playerStats = stats
});
Features

What the service
actually does.

A Spring Boot service on Postgres, with Redis or Kafka holding live queue state. Every strategy below is a swap, not a rewrite.

An LP solver, not a bucketer
Team formation is an assignment problem, so MatchKit solves it as one: OR-Tools evaluates the combinations and returns the best split, instead of pairing players greedily down a sorted list. It's the default mode, and in it a per-queue fairness gate holds any split whose imbalance exceeds the tolerance rather than ship it, until a fairer match forms or the wait cap trips. MMR and ELO are there if you arrive with a specific idea of what you want.
Ratings update themselves
Post the result, get updated ratings back: TrueSkill (μ and σ) or plain MMR. Wins, losses and K/D/A are stored per player and per match. Rating mode is a separate axis from formation mode, so you can mix them.
Queues you can tune while they run
The skill window starts at 400 points and widens by 100 every 15 seconds until the queue fills or the 60-second wait cap trips. All three numbers are per-queue and settable at runtime.
SSE, not WebSocket
Match events only travel one way, so they ride Server-Sent Events: plain HTTP, reconnects on its own, no second protocol to operate. The cost is that you can't send anything back up the stream; client-to-server stays REST.
No player PII
The player record is a username your game supplies, a region, ratings, and K/D/A. No email, no device id, no IP address; there isn't a column for one. We can't sell data we don't store, and we can't hand it over if someone asks.
Redis or Kafka for queue state
One config key. On Redis a queue is a hash keyed by player id, so two players joining never touch the same field and a join stays one write however busy the queue gets. Kafka replays compacted topics into a local view, so you get the event log, and it's eventually consistent across nodes. Pick Redis unless you want the log.
Don't use MatchKit if:

Four cases where something else fits better.

  • -You need game servers hosted or orchestrated. MatchKit doesn't do that; look at Edgegap, GameLift or Multiplay. It tells you who plays together. Where they play is yours.
  • -You want one backend for accounts, inventory, chat and leaderboards. That's Nakama or PlayFab. MatchKit is a component, and it's built to sit next to whatever you already run.
  • -Your game has no skill axis: casual, party, anything where grouping players doesn't need solving. A lobby service is cheaper and simpler. Co-op is a separate case and it's being built, but you can't configure a co-op queue yet, so today it belongs here too.
  • -You need it proven in production. It's pre-alpha and it has no users yet.
Self-hosted

You used to own
the game you bought.

The license is an Ed25519-signed file the service checks locally. It doesn't phone home; there's no endpoint for it to call. We can't revoke it, meter it, or see your usage, and neither could anyone who bought us.

Buy 1.x and every 1.x release is yours: patches, fixes, features. No renewal, no expiry. The next major version costs a small upgrade fee, and you can stay where you are instead. If MatchKit stops existing, your install keeps forming matches.

Who builds this

One developer, in their spare time, alongside a day job. Not a company, not a team, no investors. Support is best-effort and it comes from the person who wrote the code.

That's also why the self-hosted license works the way it does. If this project stops, if it gets boring or life gets in the way, the hosted service will eventually go away, because servers cost money. Your install won't. Anyone running MatchKit on their own hardware keeps running it, and we'll help you move over if you'd rather not wait and see.

See it run

There's a demo. Go read it.

A runnable Unity project that drives MatchKit end to end: it queues a whole population, watches balanced teams form on screen, then hands the roster to Mirror, Fish-Networking or Photon. The SDK is vendored in, so the repo is self-contained, and you can read exactly how the integration works before you ask us for anything.

The launch-test scene needs no netcode at all: one process spawns the players and the capsules light up by state as the solver groups them. It's the fastest way to see what the fairness gate does to a queue that can't be split fairly.

Running it against a live server needs a key, and keys are invite-only, but the source, the SDK and the integration are all readable without one. That's deliberate: judge it before you commit to it.

Engine support

Unity today. REST everywhere else.

UnitySDKUnreal EngineTBAGodotTBAJavaScript / TypeScriptTBA

There's a Unity SDK. Unreal, Godot and a JS/TS client aren't written yet, and there's no date to give you. The API is HTTP and text/event-stream, so any engine or backend talks to it with the client it already has.

Pricing

Priced for indie studios.

Hosted is free during pre-alpha: nobody pays anything, and the limits are steep. The paid tiers below are what we intend to launch with once pre-alpha ends. Billing isn't built yet.

Free
$0
no card, no expiry

  • 1,000 monthly active players
  • Every formation and rating mode, nothing is held back
  • REST + SSE, and the Unity SDK
  • 30,000 write calls per month, up to 1,000 in a day (reads are free)
  • Up to 5 active queues
  • Support: Discord, best effort
  • Free during pre-alpha: nobody pays anything yet
Request an invite
Indie
$29
per month

  • 10,000 monthly active players
  • No cap on queues or game modes
  • Searchable match history + stats API
  • Per-key usage metering
  • Support: email
Request an invite
Studio
$199
per month

  • 50,000 monthly active players
  • Then $4 per additional 1,000 players
  • Everything in Indie
  • Usage analytics in the dashboard
  • Support: email, best effort, usually within a business day
Request an invite
Scale
Contact us

  • 250,000+ monthly active players
  • Optional dedicated server: your own instance, not the shared pool
  • Quotas and rate limits set per account
  • Whatever support and uptime terms we agree, in writing
  • Support: a shared channel with us
Talk to us
Self-hostedContact usone-time perpetual license

The same build we run, on your hardware. No metering means we can't see your usage, throttle you, or take the service away from you, which is the entire point. Buy 1.x and every 1.x release after it is yours: patches, fixes, features, no renewal, no expiry. When 2.0 lands you can stay where you are indefinitely, or pay a small upgrade fee to move.

  • Docker Compose: API, dashboard, Postgres, Redis, Kafka
  • Offline Ed25519-signed license, no phone-home
  • No metering, no usage caps, no active-player counting
  • Every update to the major version you bought, free and forever
  • Next major version is a small upgrade fee, never a re-purchase
  • Player data never leaves your servers
Email us for a license

Tell me what
you're building.

The pre-alpha is invite-only. A couple of sentences about your game is all I need. I read every one, and if it's a fit I'll send you a key and a link to the quick-start.