5. Start a Search
Once the WebSocket connection is open, queue the player for a match by sending a begin_search
action.
{
"action": "begin_search",
"payload": {
"gameMode": "ranked_1v1"
}
}gameMode must match the name of a game mode you created for your tenant in the Config page
(see Account Setup) — if it doesn't exist, or isn't enabled, the search is
rejected (see below).
What happens next
When the search is registered, the server acknowledges it with SEARCH_STARTED:
{
"action": "SEARCH_STARTED",
"data": { "gameMode": "ranked_1v1", "startedAt": 1767225600 }
}startedAt is the time (epoch seconds) the player's wait is measured from. For
ping-based game modes it arrives once your pong completes the search.
Sending begin_search again for a search that is already running re-sends it, so a client that
missed the acknowledgement can recover.
The server pushes further actions back over the same connection as things happen. Once a match is made,
the client receives MATCH_FOUND — see Match Made for that payload and what
your backend receives via webhook.
To stop searching before a match is found, send:
{ "action": "cancel_search" }Possible responses
Anything that isn't a success shows up as an ERROR action:
{
"action": "ERROR",
"data": {
"code": "...",
"message": "...",
"details": { }
}
}Here's every response type your integration should be prepared to handle, grouped by what it means for you:
Auth / connection issues — can appear on connect, or mid-session if something about the ticket or connection becomes invalid:
- Bad, expired, or already-used ticket. Request a new ticket from your backend and reconnect — don't retry with the same one.
Account / billing issues — something about the tenant's plan needs attention. Surface these to you (the tenant), not the player:
- The account has used its matched player allowance for the current billing cycle (
TOKEN_QUOTA_EXCEEDED). New searches are rejected and the connection is closed; players already in the queue and matches already made are unaffected. The allowance resets each billing cycle — see how billing works. - Billing access has been suspended (e.g. a lapsed grace period after a failed payment).
- The account is on the signup waitlist and doesn't have matchmaking access yet.
Request issues — something about this specific search request:
- The requested game mode doesn't exist, or isn't enabled for the tenant's tier.
SEARCH_START_FAILED: the search couldn't be started on our side and nothing was queued, so it's safe to sendbegin_searchagain.- A required player attribute (e.g.
mmr, for MMR-based game modes) is missing from the ticket — make sure it's included inattrswhen generating the ticket.
Ping-based game modes
If gameMode refers to a Ping-based game mode, the
search doesn't join the pool immediately. Instead, expect an unsolicited action from the server:
{
"action": "PING",
"data": {
"correlationId": "..."
}
}Reply immediately, echoing the same correlationId and the gameMode you searched with:
{
"action": "pong",
"payload": {
"correlationId": "...",
"gameMode": "ranked_1v1"
}
}gameMode is required on every pong — if the server doesn't recognize the correlationId
you're replying to (it can happen, harmlessly, on a very fast reply), it uses gameMode to kick
off a fresh ping check on your behalf rather than leaving you stuck. You'll simply receive another
PING to reply to.
The round trip time is measured entirely server-side — your client doesn't need to compute or
report anything beyond replying as fast as possible. Only once a pong is matched to its
correlationId does the search actually enter the matchmaking pool; as with the MMR path,
there's no explicit acknowledgement that this succeeded — silence means the player is now
searching, and you'll next hear from the server via MATCH_FOUND, ERROR, SEARCH_SUPERSEDED,
or CLOSE_CONNECTION.
No server timeout notification
If your client never replies, the server doesn't send anything back — there's no timeout
error. Give begin_search a client-side timeout (a few seconds is plenty) and re-send it if
you haven't heard anything back by then.
A disconnect while a PING check is outstanding isn't resumable — reconnecting starts the whole
flow over from a fresh begin_search, the same as starting a new search would.
Reconnecting from another device
If the same player starts a new search from a second connection (e.g. a second device or tab) while already searching, the new connection takes over and the old one receives:
{ "action": "SEARCH_SUPERSEDED" }The old connection is then closed. Only one active search per player is supported at a time.
Next
See Match Made for what the client and your backend each receive once a match is formed.