Skip to main content

Implementing In Your Game

With a FIFO 2v2 matchmaker published (see Creating a Matchmaker), your backend wires up to it through three ticket calls: create a ticket, poll for the assigned server, and cancel if the player stops searching. This page follows that FIFO flow. The examples are TypeScript, matching the Colyseus example, but the API is plain REST and works from any language.

Backend-driven matchmaking

Your backend holds the GameFlow API key and makes every ticket call. The game client only asks your backend to "find a match" and waits for a server. Keeping the key on the backend means it never ships to players.

Game Client  ──►  Your Backend  ──►  GameFlow ticket API
"find match" holds API key create / poll / cancel

All calls go to the GameFlow API base URL and send your key in the X-Api-Key header.

1. Create a ticket

When a player starts searching, enqueue one ticket.

const res = await fetch(`${GAMEFLOW_API_URL}/matchmaking/tickets`, {
method: "POST",
headers: { "X-Api-Key": apiKey, "Content-Type": "application/json" },
body: JSON.stringify({
player_id: player.accountId,
game_id: gameId,
game_mode: "standard", // must match the matchmaker's Ticket Input
preferred_az: "us-east",
mu: 25, // neutral rating placeholder for FIFO
sigma: 8.333, // must be > 0
rating_bucket: 0,
tags: [],
}),
});

const { ticketId } = await res.json();
FieldDescription
player_idThe player being matched.
game_idYour GameFlow game id.
game_modeRoutes the ticket to the matchmaker. Must equal its Ticket Input game mode.
preferred_azThe player's region.
mu, sigmaThe player's rating. FIFO ignores it, so send neutral placeholders. sigma must be greater than 0.
rating_bucketNumeric rating bucket. Send 0 for FIFO.
tagsOptional string tags for use in Bucket or Split nodes.

A failed create is terminal (a bad request, no published matchmaker for that mode, or a bad key). There is nothing to retry, so report it and stop.

2. Poll for the assigned server

The status endpoint long-polls: it waits up to timeout_seconds and returns as soon as the ticket is assigned a server, or pending if still searching. Call it in a loop until the ticket is assigned or the player cancels.

const url =
`${GAMEFLOW_API_URL}/matchmaking/tickets/${ticketId}/status?timeout_seconds=20`;

while (searching) {
const res = await fetch(url, { headers: { "X-Api-Key": apiKey } });
const { status, connection } = await res.json();

if (status === "assigned" && connection) {
const [address, port] = splitHostPort(connection); // "host:port"
sendServerToPlayer(address, port);
break;
}
// status is "pending": the request already long-polled, so just loop again.
}

For a robust loop, treat network errors, 408, 429, and 5xx as transient (back off and retry, giving up after a few consecutive failures), and other 4xx as terminal.

3. Cancel on stop or disconnect

If the player stops searching or disconnects before matching, drop the ticket. Otherwise it lingers in the queue and gets paired with the next player, sending them to an empty server.

await fetch(
`${GAMEFLOW_API_URL}/matchmaking/tickets/${ticketId}?player_id=${playerId}`,
{ method: "DELETE", headers: { "X-Api-Key": apiKey } },
);

player_id must be the ticket owner. A 404 means the ticket was already matched or removed, so treat it as success. Cancel from both your "stop search" handler and your socket-close handler.

Receiving the match on the server

The status returns connection as host:port. Your backend forwards it to the player, who connects directly to that dedicated server.

For a FIFO matchmaker the match is formed by GameFlow, but no roster is sent to the game server. The server assigns team slots as players connect, in arrival order. This is the opposite of direct allocation, where your backend already knows the teams and passes them in the payload. Read the payload only in the allocation flow; in the matchmaking flow there is none.

Full example

The Colyseus multiplayer example is a complete, working implementation of this FIFO flow: a backend-driven Quick Match that creates a ticket, long-polls with backoff, cancels on stop and disconnect, and a Colyseus server that seats matched players into a 2v2.