Build a single-elimination bracket with automatic byes
Five teams become an eight-slot bracket with three byes for the top seeds, one opening match and three rounds through the final, and the same list always gives the same draw. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Participants
- North Stars, River Hawks, City Lions, Valley Foxes, Coastal Bears
- Participant count
- 5
- Bracket size
- 8
- Bye count
- 3
- Round count
- 3
Turn an ordered list of participant names into a complete single-elimination tournament structure. The bracket builder calculates the next power-of-two field size, inserts only the byes that are necessary, and labels every match through the final. No draw is randomized, so the same participant list always produces exactly the same bracket.
Prepare the participant list in seeding order
Start with at least two participant names and arrange them in the order you want the bracket to recognize. The first entry becomes seed 1, the second becomes seed 2, and so on. Names may identify individuals, teams, clubs, schools, projects, or any other competitors, but every entry must be a non-empty string.
Leading and trailing whitespace is removed so copied registration data does not create untidy labels. Duplicate names are preserved because two different competitors can legitimately share a display name; use qualifiers such as a city, division, or team code when readers need to distinguish them. The builder does not shuffle the field, consult rankings, or introduce randomness.
That deliberate behavior makes the output reproducible: identical input produces an identical match plan on every run. If registration order should determine placement, submit registration order. If rankings should determine placement, sort the names by ranking before calling the capability.
Keeping selection policy outside bracket construction makes the result easier to audit and lets each tournament apply its own published seeding rules without hidden assumptions.
Understand bracket size, matches, and byes
A single-elimination bracket works cleanly when its field size is a power of two: 2, 4, 8, 16, and onward. When the participant count falls between those sizes, the builder expands to the smallest power of two that can contain everyone. The difference becomes the bye count.
For example, five participants require an eight-slot bracket, so three seeded participants receive first-round byes and the remaining two play the opening contested match. Byes are assigned deterministically to the earliest seeds, while the remaining participants are paired in their submitted order. Each first-round match identifies its participant records by name and seed.
A bye match also identifies the participant who advances automatically. Later rounds contain source labels such as “Winner of match 1,” allowing a user interface or tournament system to connect results without guessing. Match numbers remain unique across the entire bracket.
The response also reports participant count, bracket size, bye count, and round count, which makes basic validation and display summaries straightforward.
Use the bracket in an event workflow
The returned rounds are ready to drive a bracket view, printable schedule, match database, or event operations checklist. Read rounds in ascending order and matches in their returned order. For opening matches, display participant names directly; when a match has a bye, advance the included competitor without requesting a score.
For later matches, replace each source label with the winner produced by the referenced match. The capability builds structure only: it does not collect scores, decide winners, schedule courts, resolve withdrawals, or reseed after a round. Those responsibilities should remain in the tournament application so its rules stay explicit.
A useful integration stores the generated bracket as the event’s initial immutable plan, then records results separately against match numbers. This preserves an audit trail even when a competitor withdraws or an organizer corrects a result. Validate the final participant list before publishing because changing its order changes the bracket.
What you can do with it
Create a community tournament
Convert the final signup list into a numbered bracket that volunteers can publish and operate.
Add brackets to event software
Generate predictable match records and winner references when registration closes.
Plan an internal competition
Build a clear knockout structure for teams, games, pitches, demos, or classroom contests.
FAQ
How are byes calculated?
The field expands to the smallest power of two that fits every participant. The empty slots are byes.
Who receives a bye?
Byes go to the earliest participants in the submitted seeding order, making assignment deterministic.
Does the builder randomize names?
No. It never uses randomness. Sort or shuffle the list before submitting it if your tournament requires a draw.
Can two participants have the same name?
Yes. Duplicate display names are preserved, and their seed numbers still distinguish their bracket entries.
Does it track scores and winners?
No. It creates the initial bracket and match progression references; scorekeeping belongs to the consuming application.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/game/tournament-bracket-build \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"participants":["North Stars","River Hawks","City Lions","Valley Foxes","Coastal Bears"]}'const res = await fetch("https://api.kit.forhosting.com/game/tournament-bracket-build", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"participants": [
"North Stars",
"River Hawks",
"City Lions",
"Valley Foxes",
"Coastal Bears"
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/game/tournament-bracket-build",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"participants": [
"North Stars",
"River Hawks",
"City Lions",
"Valley Foxes",
"Coastal Bears"
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/game/tournament-bracket-build", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"participants":["North Stars","River Hawks","City Lions","Valley Foxes","Coastal Bears"]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"participants":["North Stars","River Hawks","City Lions","Valley Foxes","Coastal Bears"]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/game/tournament-bracket-build", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"participants": [
"North Stars",
"River Hawks",
"City Lions",
"Valley Foxes",
"Coastal Bears"
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "game.tournament_bracket_build",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
The input order is treated as seeding order, making the result stable, explainable, and easy to reuse in an event page, registration system, spreadsheet workflow, or competition API.
Use the bracket in an event workflow
Browser use is available for interactive planning, while an API request costs $0.002 when bracket creation is automated inside registration, league, or event-management software.
Technical questions
How many participants are required?
At least two participant names are required. A smaller list returns an invalid_input error.
What does an API request cost?
Each API request costs $0.002. The browser experience can run the same deterministic bracket logic locally.