Setup
Use this client on your server. Your exact origin must be Bankroll Verified and serve a signed manifest containing yourappKey. No matchmaking capability is needed.
Take
player from a verified session on your server. App authentication does
not authenticate a player field submitted by a browser. Authorize each user’s
access before returning tickets: app credentials can discover the whole app.
Model
Payloads contain shared game conditions, such as a seed or target. Keep results
and private data in your app. A player may have multiple tickets, but two tickets
with the same
player never pair.
API
Types are exported from@joinbankroll/sdk/matchmaking:
undefined;
Date, BigInt, functions, sparse arrays, and cyclic objects are not JSON inputs.
Create and play
Build the input from the app action you already recorded and the verified session. Retain the original fields for retries, including any rating or cutoff.Guarantees
- Idempotent creation. Identical input returns the ticket’s current state.
JSON object key order does not matter. Changing any field for an admitted ID
returns
ticket_conflict, including after it becomes terminal. - Fixed queue policy. The first accepted input fixes the queue’s
sizeandratingpolicy, even if that ticket is already expired. Later disagreement returnsqueue_conflict. Use a new key to change policy. Only size2is supported. - Final matching. A ticket belongs to at most one match. Both tickets return the same match; neither returns to the pool.
- Atomic cancellation.
cancelTicketreturnsmatchedif pairing won, orcancelledif cancellation won. It never returnswaiting. Retrying returns the same terminal outcome. - Cancellation before creation. Cancelling an unknown ID records a permanent
cancellation with
admission: null. A delayed creation for that ID returns it without admission, regardless of the proposed fields. - No default expiry. Omit
expiresAtto wait indefinitely. A waiting ticket at or past its app-selected cutoff becomescancelledwith reasonexpiredwhen read, considered for pairing, or cancelled. It cannot match past the cutoff. A past cutoff on creation cancels immediately; a completed match never expires. - Request-driven progress. There are no background timers or automatic rematches. Reads evaluate expiry; new admissions attempt matching. Your app decides when to poll, cancel, or resolve a non-playing opponent.
- Discovery with admission. Every accepted ticket is discoverable in its app as soon as it can match. Terminal tickets and matches remain discoverable; there is no deletion or ID-reuse operation.
Ratings
A rated ticket requires a queue rating policy.initial must be nonnegative,
widenPerSecond positive, and optional max at least initial. All are finite.
At admission time, each waiting candidate’s tolerance is:
max leaves the band uncapped. waitingSeconds is the older ticket’s
elapsed wait; the joining ticket contributes no wait. The oldest compatible
candidate wins. Rated tickets do not pair with unrated tickets. When neither
has a rating, pairing is FIFO among different players.
Recover a lost ID or reply
listTickets() discovers all of your app’s tickets, including matched and
cancelled ones. It does not require a queue, player, or ticket ID:
player and id filters combine. Keep the same filters on subsequent
pages and pass the cursor unchanged. Pages contain at most 25 tickets in creation
order. A traversal covers tickets present when its first page began; states are
current when each page is read. Start another traversal for later admissions or
state changes. Unknown IDs return an empty page, not a cancellation.
Cancelling an unknown ID has no player association, so find that cancellation
by ID or app-wide listing. A player filter cannot find it.
This removes the lost-ID orphan: admission and discovery are one guarantee,
including if a crash loses the response or pairing finishes before recovery.
Even a lost player ID is recoverable through app-wide listing. Using an existing
app action’s ID also makes retries and reconciliation straightforward. Recovery
requires access to the same verified app identity; it cannot make an abandoned
app return or a player finish a round.
Lifecycle and caller flow
Terminal records remain discoverable.Errors
MatchmakingError exposes code and status (HTTP status, or null for a local
failure). A body-read timeout can preserve HTTP 200; handle the error by code.
Calls time out after 30 seconds and are never automatically retried.
A timeout or missing response is not proof that creation or cancellation failed.
Do not invent a replacement ID to retry the same action.
HTTP
Other stacks usePOST https://api.joinbankroll.com/api/matchmaking with
Content-Type: application/json and app authentication.
The successful response is the ticket or page directly. Refusals return
{ "error": "<code>" }; service unavailability returns 503. invalid_response
is an SDK error, not an API response code.