Core Concepts
Six ideas cover the whole system. The rest of the documentation is detail on top of them.
flowchart LR
T[Ticket<br/>one player or party] --> P[(Pool<br/>everyone waiting)]
P --> E{{Engine<br/>runs every tick}}
E -->|match formed| M[Match<br/>teams + host]
E -.->|nothing yet| P
M --> O[Outcome<br/>pushed to your backend]
Ticket
Section titled “Ticket”A ticket is one player, or one party, waiting to be matched. It is the unit of matchmaking, and your backend creates it with an ID you choose.
A party is one ticket containing several players, never several tickets. The engine will not split a ticket across teams, so “we queued together, we play together” is a guarantee and not a preference.
Two payloads ride along, and they do opposite jobs:
engine_inputis what the engine reads: players, skill ratings, measured latencies, attributes.metadatais what nobody reads. IVK Match never looks inside it and hands it back verbatim on every outcome about that ticket. Put your session and party IDs here and you will not need a lookup table keyed by ticket ID.
Queue and ruleset
Section titled “Queue and ruleset”A queue groups players who want the same kind of match. It is also the unit of configuration: one queue is described completely by one declaration covering team shape, latency budgets, skill tolerance, and attribute rules.
A ruleset is a named matching configuration inside a queue. One queue can run several side by side (different team sizes, playlists, or skill brackets), and each ticket picks which rulesets it competes in. Most integrations start with one queue and one ruleset.
See Queue Configuration.
The pool is every ticket currently waiting in a queue, and it is the engine’s working set.
Pool size drives match quality more than any parameter you can set. More people waiting means more candidates to choose between, which means closer skill matches and better connections. A thinly-populated queue produces worse matches than a busy one under identical configuration, and no amount of tuning changes that.
Tick and engine
Section titled “Tick and engine”The engine runs on a tick, once per second by default. Matching is not event-driven: a ticket arriving does not trigger a matching attempt.
The engine, Nemesis, is stateful and iterative. It does not solve the pool from scratch each tick. It keeps working on the matches it is assembling and improves them tick by tick: adding a player here, swapping one there, deciding a group has come together well enough to ship. That has two consequences people rarely expect:
- A match does not form the instant enough players are present. The engine will hold a nearly-complete group for a few more ticks if the pool suggests it can do better.
- The engine paces itself against the pool. When the pool is thin it matches conservatively, because every match it forms removes candidates the next one could have used.
Every parameter you can set is either a hard filter (may these players share a match at all) or a preference used to score the options the filters allowed. Weights only mean anything relative to each other.
A match is the engine’s output: a set of tickets, divided into teams, with a chosen host to run on. Its ID is a UUID and the natural key for the session you are about to create.
Host selection deserves a note here. IVK Match never interprets host identifiers. Whatever strings you send as latency keys come back as the match’s preferred host, plus every alternative acceptable to all tickets in the match. Send the identifiers your provisioning layer already uses and this becomes a pass-through instead of a translation layer. The acceptable list then doubles as a fallback when provisioning fails.
Outcome
Section titled “Outcome”An outcome is anything IVK Match has to tell you asynchronously: a match formed, tickets expired, tickets were removed. Outcomes are pushed to your backend.
Three properties shape how you write the consumer.
A formed match is a commitment. By the time the outcome exists, those tickets have already left the pool and those players are no longer matchmaking. Drop the outcome and they are stranded on a screen that will never advance. If you cannot honour a match, most often because provisioning failed, you must actively compensate by returning the tickets to the pool.
Delivery is at-least-once. Every sink can deliver the same outcome twice: after a retry, a reconnect, or a restart between write and acknowledgement. Key session creation on the match ID and duplicates become harmless.
Ordering is per queue. Outcomes for one queue arrive in the order they happened. Independent queues are independent.
See Outcome Delivery.
How long it all takes
Section titled “How long it all takes”Queue wait and server provisioning dominate; the engine contributes at most one tick. The breakdown is in Integration Flow § Where the time goes.
Integration Flow walks the full sequence, and the guides beside it cover cancellation, provisioning failure, timeouts, and backfill. Every term used across the documentation is defined in the Glossary.