Skip to content

Create a tournament or 1v1 challenge

POST
/api/tournaments/create
curl --request POST \
--url https://foxleague.ai/api/tournaments/create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "challenge_deadline_minutes": 1, "deadline": "2026-04-15T12:00:00Z", "description": "example", "developer_mode": true, "entry_fee_foxsy": 1, "expected_platform_fee_percent": 1, "format": "example", "has_third_place_match": true, "home_and_away": true, "max_teams": 1, "min_teams": 1, "organizer_fee_tx_hash": "example", "organizer_only": true, "ovr_max": 1, "ovr_min": 1, "round_interval_minutes": 1, "snapshot_at": "2026-04-15T12:00:00Z", "sponsor_prize_foxsy": 1, "starts_at": "2026-04-15T12:00:00Z", "target_user_id": 1, "tier": "example", "title": "example", "whitelist_user_ids": [ 1 ] }'

Creates a standard tournament or, with max_teams: 2, a 1v1 challenge. In a free tournament you get the first seat at once, unless organizer_only is set. A paid tournament (Silver and Gold; a Bronze with a fee once the competition levels are live) is first created on chain; you then pay the entry fee and join with POST /api/tournaments/{id}/join like any player. While GET /api/config answers tournament_defaults.standard_create_and_join: true, the create page makes a paid tournament you play in with POST /api/tournaments/challenges/authorize instead: one transaction of yours creates it and pays your entry fee. The answer is the tournament as first written: a paid one reads status: "pending_sc" and sc_tournament_id: null here, so read it again before joining. A standard tournament that is not a developer one reserves a time window on the schedule and is refused when that window overlaps another tournament’s. An optional OVR range (ovr_min, ovr_max) seats only teams whose best XI OVR is inside it: the average OVR of the strongest XI a manager can field from the cards they own. It is checked once, when a team joins. While registration is open you can widen it, never narrow it (POST /api/tournaments/{id}/ovr-range). A Champions FoxLeague tournament (an admin only) takes a snapshot_at and is always organized: its seats go to the teams it invites from the leaderboard frozen at that date, in three waves. A paid one is created on chain open to invited wallets only.

Who: a signed-in player.

Rate limit: one active 1v1 challenge per wallet (as creator or opponent), one active tournament you created to play in and one active tournament you organize.

Refusals:

  • Not registered: the wallet has no player account.
  • Invalid format '<format>'. Valid: knockout, groups_knockout, round_robin, swiss, league_knockout: unknown format.
  • Champions FoxLeague invites its teams from the leaderboard, so it takes no OVR range.: ovr_min or ovr_max on league_knockout.
  • A developer tournament is played by uploaded binaries, so it takes no OVR range.: ovr_min or ovr_max with developer_mode: true.
  • The OVR range takes whole numbers from 1 to 100.: ovr_min or ovr_max below 1 or above 100.
  • The minimum OVR cannot be above the maximum OVR.: ovr_min above ovr_max.
  • Your best XI OVR is <ovr> (the average OVR of the strongest XI you can field from the cards you own), outside the OVR range you set (<range>). Set a range your team is in.: you take a seat (not organizer_only; a 1v1 challenger always does) and your best XI OVR is outside your own range. <range> reads like 30 to 40, at most 35 or at least 30.
  • You own no cards to measure against the OVR range.: a range while you take a seat and none of your cards fits a lineup slot.
  • Champions FoxLeague tournaments are created by an admin only.: league_knockout from a player.
  • Champions FoxLeague is switched off. An admin turns on tournament.league_knockout_enabled first.: league_knockout while the admin has not switched the format on.
  • A Champions FoxLeague tournament needs a snapshot date (snapshot_at): the leaderboard is frozen then and the invitations go out.: league_knockout without snapshot_at.
  • The snapshot date must be in the future.
  • The snapshot date must be at least <window> before the registration deadline.: the window is an admin setting, 4 days by default.
  • snapshot_at is only for Champions FoxLeague tournaments.: snapshot_at for another format.
  • A Champions FoxLeague tournament invites from the leaderboard: it takes no invite list.: league_knockout with a non-empty whitelist_user_ids.
  • A Champions FoxLeague tournament is played by the NFT teams the leaderboard ranks: it cannot be a developer tournament.: league_knockout with developer_mode: true.
  • Your team is still in <title>, a Champions FoxLeague tournament that has started. You can join or create another tournament once your team is out or <title> ends. 1v1 challenges and ranked matches stay open to you.: a tournament you would play in (not organizer-only, not a developer tournament, not a 1v1 challenge).
  • A prize from FoxLeague is only for Champions FoxLeague tournaments.: sponsor_prize_foxsy for another format.
  • A prize from FoxLeague needs a paid Champions FoxLeague tournament (an entry fee): the contract holds the prize.: a prize on a free one. A paid Bronze (once the competition levels are live) may carry a prize.
  • The prize from FoxLeague must be at least 1 FOXSY.
  • This wallet is not an approved sponsor: the owner approves it once on the contract. Create the tournament without a prize or ask the owner to approve this wallet.: a prize from a wallet the owner has not approved on the contract.
  • Could not check on the contract whether this wallet may give a prize. Please retry or create the tournament without a prize.: the contract could not be read; nothing was created.
  • Invalid tier '<tier>'. Valid: bronze, silver, gold: unknown tier.
  • Invalid max_teams <max_teams> for format '<format>'. Allowed: <sizes>: a size the format does not allow; <sizes> lists the allowed ones, for example 2, 4, 8, 16, 32.
  • min_teams must be >= <minimum> for format '<format>': min_teams below the format’s minimum.
  • min_teams cannot exceed max_teams.
  • Knockout tournaments start only when the bracket is full. Set min and max teams equal (<max_teams>) so every team has an opponent (no byes).: a knockout with min_teams different from max_teams.
  • 1v1 challenges are Silver or Gold; Bronze is for developer challenges only: a Bronze 1v1 challenge without developer_mode.
  • challenge_deadline_minutes must be one of 30, 60, 120, 240, got <minutes>.
  • You cannot challenge yourself. Choose a different opponent: target_user_id is your own id.
  • Targeted opponent not found. They need to register on the platform first: no player has this target_user_id.
  • Developer challenges can only be created by a verified, active developer team. Upload and validate a binary in Developers Hub first: developer 1v1 challenge without an active verified developer team of yours.
  • Developer Mode needs an admin's approval. Request access from the Developer page.: developer 1v1 challenge while an admin has not approved your Developer Mode access (or revoked it).
  • That opponent doesn't have a verified, active developer team, so they can't accept a developer challenge: developer 1v1 challenge whose target has no such team, no team or no admin’s approval for Developer Mode.
  • You already have an active 1v1. Finish it or cancel it first.: you already created or joined an open or running 1v1 challenge.
  • You have a tournament match within the hour. Finish it first.: 1v1 challenge from an hour before a tournament or challenge match of yours until its result is out. The same holds from an hour before your group’s last kickoff until the group’s results are out and from an hour before your Swiss round match until all the round’s results are out.
  • Deadline must be in the future.
  • Tournament must start at least 1 hour from now.
  • starts_at must be after the registration deadline: starts_at is not more than five minutes after deadline.
  • Time slot conflicts with tournament #<id> '<title>'. Choose a different time.: the reserved window overlaps another tournament’s.
  • Time slot is held by a tournament that is being created. Choose a different time.: the reserved window overlaps the booking held for a tournament whose creator has not paid yet. Your own tournament whose payment window has closed holds nothing against you: the tournament you create at its time slot replaces it.
  • You already have an active tournament you are organizing. Complete or cancel it before creating another.: organizer_only while you already organize an active tournament.
  • You already have an active tournament you are playing in. Complete or cancel it before creating another.: you already created an active standard tournament to play in.
  • Bronze tournaments cannot have an entry fee: a Bronze fee before the competition levels are live.
  • Bronze: <min>-<max> FOXSY: once the competition levels are live, a player’s Bronze fee outside the Bronze band, 0 included (an admin may still create a free Bronze).
  • Developer tournaments and challenges are free Bronze: a fee on a developer Bronze tournament or challenge.
  • Entry fee cannot be negative.
  • Silver: <min>-<max> FOXSY: a Silver fee outside the Silver range, 0 included.
  • Gold: >=<min> FOXSY: a Gold fee below the Gold minimum, 0 included.
  • Round interval must be 30-1440 minutes: round_interval_minutes above 1440.
  • Title must be 1-100 characters: blank or too long title.
  • Description must be under 1000 characters.
  • Tournament cannot start more than 90 days from now.
  • One or more invited teams were not found. They need to register first.: an id in whitelist_user_ids is not a player.
  • A private tournament has <max_teams> seats: you plus <max_teams - 1> invited teams. You invited <count>. Remove some or raise the maximum.: whitelist_user_ids and your own seat do not fit max_teams. With organizer_only: A private tournament you organize has <max_teams> seats, all for invited teams. You invited <count>. Remove some or raise the maximum.
  • A private tournament can only be filled by the teams you invite plus yourself. You invited <count>, so at most <capacity> can join, which is below the minimum of <min_teams>. Invite more teams or lower the minimum.: too few invitations for min_teams (without plus yourself when you organize only).
  • Could not create the tournament right now. Please retry.: the tournament could not be stored; nothing was created.
  • Paid tournaments are not available right now. Please try again later.: a Silver or Gold tournament while paid tournaments cannot be created.
  • Chain is temporarily unavailable. Please retry shortly.: paid tournament while the chain cannot be reached; nothing was created.
  • The tournament could not be created on chain, so it was cancelled. Please try again.
  • On-chain tournament creation could not be confirmed yet. The network may not be producing blocks; the tournament stays pending until its creation can be confirmed. Please check the tournament list before retrying.: the tournament stays pending_sc until its creation on chain is confirmed.
  • Developer tournaments require a validated developer team to enter. Create it as organizer-only to run it without playing. Otherwise validate a binary in Developers Hub first.: free developer tournament, you play in it and you have no verified developer binary.
  • You need at least 18 unlisted players to enter a match. You currently have <have> (<short> short). Cancel <short> <listing|listings> on the Marketplace or buy <short> more <NFT|NFTs> to play again.: while the 18-player rule is in force, your wallet holds fewer than 18 players that are not listed for sale.
  • Tournament creation failed. Could not snapshot your team: <reason>: free tournament where your squad cannot take its seat; <reason> is one of the squad refusals of POST /api/tournaments/{id}/join. Nothing was created.
  • Tournament creation failed: your team could not be added to it. Please try again.: nothing was created.
Media type application/json

The settings of a new tournament or 1v1 challenge.

object
challenge_deadline_minutes

1v1 challenge only: minutes the challenge stays open, 30, 60, 120 or 240 (default 60). Kickoff is five minutes after it closes; when an opponent accepts, registration closes at once and the match is scheduled shortly after.

integer | null format: int32
deadline
required

Registration closes at this time (RFC 3339); it must be in the future. Required but ignored for a 1v1 challenge.

string format: date-time
description

Optional text, at most 1000 characters.

string | null
developer_mode

Only teams with a verified developer binary may join. Available on every format except Champions FoxLeague.

boolean | null
entry_fee_foxsy

Entry fee in whole FOXSY. Bronze: 0 or absent until the competition levels go live; from then a Bronze needs a fee inside the Bronze band, a developer one stays free. Silver and Gold need a fee inside the tier’s range; the refusal names the range.

integer | null format: int64
expected_platform_fee_percent

Paid private tournament only: the platform fee, in percent, your page showed (platform_fee_percent of private_tournament_prize_split in GET /api/config). A different percent is refused before anything is written: read the config again. Omitted: nothing is compared.

integer | null format: int64
format
required

knockout, groups_knockout, round_robin, swiss or league_knockout (Champions FoxLeague: created by an admin only, while the admin has switched the format on). A 1v1 challenge is knockout.

string
has_third_place_match

Adds a match for third place between the losing semifinalists. Default false.

boolean | null
home_and_away

round_robin only: every pair of teams meets twice. Ignored for other formats.

boolean | null
max_teams
required

Seats. knockout: 2, 4, 8, 16 or 32 (2 makes a 1v1 challenge). groups_knockout: 8, 16, 32 or 64. round_robin: 3 to 20. swiss: 3 to 32. league_knockout: 36.

integer format: int32
min_teams
required

Teams needed to start; with fewer at the deadline the tournament is cancelled. At least 2 for knockout, 6 for groups_knockout, 36 for league_knockout and 3 for round_robin and swiss; at most max_teams. Equal to max_teams for knockout and league_knockout.

integer format: int32
organizer_fee_tx_hash

The hash of your shopPay payment of the deposit and, on a private tournament, the fee: 64 hexadecimal characters. Needed once the organizer fees apply and the tournament books the calendar; ask POST /api/tournaments/organizer-fee/quote for the amount first.

string | null
organizer_only

Standard tournament only: you run the tournament without a seat and cannot join it later.

boolean | null
ovr_max

Optional highest best XI OVR a joining team may have: a whole number from 1 to 100, not below ovr_min.

integer | null format: int32
ovr_min

Optional lowest best XI OVR a joining team may have: a whole number from 1 to 100, not above ovr_max. Not for Champions FoxLeague or a developer tournament. If you take a seat, your own best XI OVR must be inside the range.

integer | null format: int32
round_interval_minutes

Minutes between one match’s kickoff and the next: the tournament plays its matches one after another. Default 30; a lower value counts as 30; at most 1440.

integer | null format: int32
snapshot_at

Champions FoxLeague only (required there): when the leaderboard is frozen and the first invitation wave goes out. In the future and at least 4 days (an admin setting) before deadline. Refused for every other format.

string | null format: date-time
sponsor_prize_foxsy

Champions FoxLeague only, optional: a prize from FoxLeague in whole FOXSY, at least 1, paid by the tournaments contract to the top 24 by how far they got: 4 shares to each quarter-finalist, 2 to each round-of-16 loser, 1 to each play-off loser (56 shares, 57.1, 28.6 and 14.3 percent). Only on a Silver or Gold tournament and only when your wallet is an approved sponsor on the contract. Your wallet deposits it after the create, before the snapshot.

integer | null format: int64
starts_at
required

Kickoff of the first match (RFC 3339): more than one hour from now, more than five minutes after deadline and at most 90 days ahead. Required but ignored for a 1v1 challenge.

string format: date-time
target_user_id

1v1 challenge only: the user id of the only opponent who may accept. Not your own id.

integer | null format: int32
tier
required

bronze, silver or gold. Bronze is free until the competition levels go live; from then a player’s Bronze costs the Bronze band (tournament_fee_bounds.bronze_min to bronze_max). Silver and Gold are paid in FOXSY. A 1v1 challenge is Silver or Gold; Bronze only for a developer challenge.

string
title
required

Name of the tournament, 1 to 100 characters, not blank.

string
whitelist_user_ids

Standard tournament only, never Champions FoxLeague (its invitations come from the leaderboard): user ids of the teams you invite. A non-empty list makes the tournament private. Your own id and repeated ids are dropped. The list fits the seats: at most max_teams - 1 ids when you play, max_teams with organizer_only.

Array<integer> | null
Example generated
{
"challenge_deadline_minutes": 1,
"deadline": "2026-04-15T12:00:00Z",
"description": "example",
"developer_mode": true,
"entry_fee_foxsy": 1,
"expected_platform_fee_percent": 1,
"format": "example",
"has_third_place_match": true,
"home_and_away": true,
"max_teams": 1,
"min_teams": 1,
"organizer_fee_tx_hash": "example",
"organizer_only": true,
"ovr_max": 1,
"ovr_min": 1,
"round_interval_minutes": 1,
"snapshot_at": "2026-04-15T12:00:00Z",
"sponsor_prize_foxsy": 1,
"starts_at": "2026-04-15T12:00:00Z",
"target_user_id": 1,
"tier": "example",
"title": "example",
"whitelist_user_ids": [
1
]
}

Success or a refusal: read success (the refusals are in the description).

Media type application/json
object
code

A machine-readable reason next to error, set only where the caller must act differently. tx_pending: the payment was not refused but could not be verified yet; keep the transaction hash and confirm again with the same hash, never pay twice.

string | null
data

The answer. Present when success is true.

object
away_penalty

Completed 1v1 challenge rows decided on penalties: shootout goals of the away side. Absent otherwise.

integer | null format: int32
away_score

Completed 1v1 challenge rows of the tournament lists: goals of the away side. Absent otherwise.

integer | null format: int32
blocking_window_end

End of that reserved window (RFC 3339): one hour after the tournament’s booked play time, about 3 minutes per match without the time between games; null when there is none. This is not when the tournament ends: it can keep playing after its window for hours or days.

string | null format: date-time
blocking_window_start

Start of the time window a standard tournament reserves on the schedule, one hour before kickoff (RFC 3339). No other tournament may reserve an overlapping window. null for 1v1 challenges and developer tournaments.

string | null format: date-time
cancelled_at

When the tournament was cancelled (RFC 3339); null when it was not.

string | null format: date-time
challenge_deadline_minutes

1v1 challenge: the minutes it was opened for. null for a standard tournament.

integer | null format: int32
completed_at

When the tournament completed (RFC 3339); null before.

string | null format: date-time
created_at
required

When the tournament was created (RFC 3339).

string format: date-time
creator_badge

1v1 challenge rows of the tournament lists: the creator’s team badge. Absent otherwise.

string | null
creator_ovr

1v1 challenge rows still to be played (not completed nor cancelled, not a developer one): the creator’s team OVR, one decimal, its best XI OVR (the average OVR of the strongest XI it can field from the cards it owns now (for every formation in Tactics the best card of each position for its slots, each card in its own position, the highest average kept; cards listed for sale count)). Absent otherwise and when no card it owns fits a slot.

number | null format: double
creator_ovr_formation

The formation the creator’s best XI is built in, such as 4-3-3. Absent with creator_ovr.

string | null
creator_team_name

1v1 challenge rows of the tournament lists: the creator’s team name. Absent otherwise.

string | null
creator_user_id
required

User id of the creator (the organizer).

integer format: int32
deadline
required

Registration closes at this time (RFC 3339).

string format: date-time
decided_by

Completed 1v1 challenge rows of the tournament lists: regular, extra_time or penalties. Absent otherwise.

string | null
description

Text written by the creator; null when none.

string | null
developer_mode

true when only teams with a verified developer binary may join.

boolean | null
distribute_tx_hash

Completed 1v1 challenge rows of the tournament lists: hash of the prize payout transaction. Absent otherwise.

string | null
entry_fee_foxsy
required

Entry fee in whole FOXSY; 0 for a free tournament (every Bronze before the competition levels go live, a developer one always).

integer format: int64
featured
required

true for a tournament the game features: it is listed first and enters the hall of fame when it completes.

boolean
format
required

knockout, groups_knockout, round_robin, swiss or league_knockout (Champions FoxLeague: 36 teams in one league table drawn from four pots, then two-legged knockout ties up to a single-match final).

string
has_third_place_match
required

true when a match for third place is played. A Champions FoxLeague tournament always plays one, before its final.

boolean
home_and_away

true for a round robin where every pair of teams meets twice.

boolean | null
home_penalty

Completed 1v1 challenge rows decided on penalties: shootout goals of the home side. Absent otherwise.

integer | null format: int32
home_score

Completed 1v1 challenge rows of the tournament lists: goals of the home side. Absent otherwise.

integer | null format: int32
home_user_id

Completed 1v1 challenge rows of GET /api/tournaments: user id of the home side, to match the score to the teams (the creator is not always at home). Absent otherwise.

integer | null format: int32
id
required

The tournament id.

integer format: int64
is_private

true when only invited teams may join.

boolean
max_teams
required

Seats. 2 for a 1v1 challenge.

integer format: int32
min_teams
required

Teams needed to start; with fewer at the deadline the tournament is cancelled.

integer format: int32
opponent_badge

1v1 challenge rows of the tournament lists: the opponent’s team badge once an opponent holds the second seat. Absent otherwise.

string | null
opponent_ovr

The opponent’s team OVR, read like creator_ovr, once an opponent holds the second seat. Absent otherwise.

number | null format: double
opponent_ovr_formation

The formation the opponent’s best XI is built in. Absent with opponent_ovr.

string | null
opponent_team_name

1v1 challenge rows of the tournament lists: the opponent’s team name once an opponent holds the second seat. Absent otherwise.

string | null
organizer_only

Tournament detail only: true when the creator runs the tournament without a seat. Absent elsewhere.

boolean | null
ovr_max

The highest best XI OVR a team may have to join, a whole number from 1 to 100. Absent when there is none. While registration is open its creator or an admin can raise it or remove it; it never drops.

integer | null format: int32
ovr_min

The lowest best XI OVR a team may have to join, a whole number from 1 to 100. Absent when there is none. The best XI OVR is the average OVR of the strongest XI a manager can field from the cards they own; it is checked once, when a team joins. While registration is open its creator or an admin can lower it or remove it (POST /api/tournaments/{id}/ovr-range); it never rises.

integer | null format: int32
participant_count

Seats taken. Filled by GET /api/tournaments; null in other answers.

integer | null format: int64
round_interval_minutes
required

Minutes between one match’s kickoff and the next.

integer format: int32
runner_up_user_id

User id of the runner-up, set when the tournament completes; null before.

integer | null format: int32
sc_tournament_id

Id of the tournament on chain (equal to id) for a paid tournament once it is created there; null for a free tournament.

integer | null format: int64
started_at

When registration closed and the draw was made (RFC 3339); null before.

string | null format: date-time
starts_at
required

Kickoff of the first match (RFC 3339).

string format: date-time
status
required

open: registration is open. pending_sc: a paid tournament is being created on chain and cannot be joined yet. active: registration closed and the tournament is under way. completed: finished, podium set. cancelled: too few teams at the deadline or cancelled by its creator. awaiting_payment: a challenge or tournament its creator authorized with POST /api/tournaments/challenges/authorize and has not paid yet; only its creator is ever answered it.

string
target_user_id

Targeted 1v1 challenge: user id of the only opponent who may accept. Given to the creator and the target only; null for everyone else and for any other tournament.

integer | null format: int32
targeted

true for a 1v1 challenge locked to one opponent. Absent otherwise.

boolean
targeted_to_you

true when you are the opponent a targeted 1v1 challenge is locked to. Absent otherwise.

boolean
third_place_user_id

User id of the third-placed team, set when the tournament completes; null before and when no third place is decided.

integer | null format: int32
tier
required

bronze, silver or gold. A Bronze with an entry fee (possible once the competition levels are live) is paid like Silver; one without is free.

string
title
required

Name of the tournament.

string
winner_user_id

User id of the winner, set when the tournament completes; null before.

integer | null format: int32
error

Why the request was refused, in plain words. Present when success is false.

string | null
success
required

true when the request did what it asked. false is a refusal: read error.

boolean
Example
{
"data": {
"blocking_window_end": "2026-10-04T19:24:00Z",
"blocking_window_start": "2026-10-04T17:00:00Z",
"cancelled_at": null,
"challenge_deadline_minutes": null,
"completed_at": null,
"created_at": "2026-10-01T09:12:44.518204Z",
"creator_user_id": 57,
"deadline": "2026-10-04T17:00:00Z",
"description": "Eight teams, straight knockout.",
"developer_mode": false,
"entry_fee_foxsy": 1000,
"featured": false,
"format": "knockout",
"has_third_place_match": true,
"home_and_away": false,
"id": 419,
"is_private": false,
"max_teams": 8,
"min_teams": 8,
"participant_count": null,
"round_interval_minutes": 30,
"runner_up_user_id": null,
"sc_tournament_id": null,
"started_at": null,
"starts_at": "2026-10-04T18:00:00Z",
"status": "pending_sc",
"target_user_id": null,
"third_place_user_id": null,
"tier": "silver",
"title": "Sunday Silver Cup",
"winner_user_id": null
},
"success": true
}

The request body is not valid JSON.

Media type application/json
object
code

A machine-readable reason next to error, set only where the caller must act differently. tx_pending: the payment was not refused but could not be verified yet; keep the transaction hash and confirm again with the same hash, never pay twice.

string | null
data

The answer. Present when success is true.

object
away_penalty

Completed 1v1 challenge rows decided on penalties: shootout goals of the away side. Absent otherwise.

integer | null format: int32
away_score

Completed 1v1 challenge rows of the tournament lists: goals of the away side. Absent otherwise.

integer | null format: int32
blocking_window_end

End of that reserved window (RFC 3339): one hour after the tournament’s booked play time, about 3 minutes per match without the time between games; null when there is none. This is not when the tournament ends: it can keep playing after its window for hours or days.

string | null format: date-time
blocking_window_start

Start of the time window a standard tournament reserves on the schedule, one hour before kickoff (RFC 3339). No other tournament may reserve an overlapping window. null for 1v1 challenges and developer tournaments.

string | null format: date-time
cancelled_at

When the tournament was cancelled (RFC 3339); null when it was not.

string | null format: date-time
challenge_deadline_minutes

1v1 challenge: the minutes it was opened for. null for a standard tournament.

integer | null format: int32
completed_at

When the tournament completed (RFC 3339); null before.

string | null format: date-time
created_at
required

When the tournament was created (RFC 3339).

string format: date-time
creator_badge

1v1 challenge rows of the tournament lists: the creator’s team badge. Absent otherwise.

string | null
creator_ovr

1v1 challenge rows still to be played (not completed nor cancelled, not a developer one): the creator’s team OVR, one decimal, its best XI OVR (the average OVR of the strongest XI it can field from the cards it owns now (for every formation in Tactics the best card of each position for its slots, each card in its own position, the highest average kept; cards listed for sale count)). Absent otherwise and when no card it owns fits a slot.

number | null format: double
creator_ovr_formation

The formation the creator’s best XI is built in, such as 4-3-3. Absent with creator_ovr.

string | null
creator_team_name

1v1 challenge rows of the tournament lists: the creator’s team name. Absent otherwise.

string | null
creator_user_id
required

User id of the creator (the organizer).

integer format: int32
deadline
required

Registration closes at this time (RFC 3339).

string format: date-time
decided_by

Completed 1v1 challenge rows of the tournament lists: regular, extra_time or penalties. Absent otherwise.

string | null
description

Text written by the creator; null when none.

string | null
developer_mode

true when only teams with a verified developer binary may join.

boolean | null
distribute_tx_hash

Completed 1v1 challenge rows of the tournament lists: hash of the prize payout transaction. Absent otherwise.

string | null
entry_fee_foxsy
required

Entry fee in whole FOXSY; 0 for a free tournament (every Bronze before the competition levels go live, a developer one always).

integer format: int64
featured
required

true for a tournament the game features: it is listed first and enters the hall of fame when it completes.

boolean
format
required

knockout, groups_knockout, round_robin, swiss or league_knockout (Champions FoxLeague: 36 teams in one league table drawn from four pots, then two-legged knockout ties up to a single-match final).

string
has_third_place_match
required

true when a match for third place is played. A Champions FoxLeague tournament always plays one, before its final.

boolean
home_and_away

true for a round robin where every pair of teams meets twice.

boolean | null
home_penalty

Completed 1v1 challenge rows decided on penalties: shootout goals of the home side. Absent otherwise.

integer | null format: int32
home_score

Completed 1v1 challenge rows of the tournament lists: goals of the home side. Absent otherwise.

integer | null format: int32
home_user_id

Completed 1v1 challenge rows of GET /api/tournaments: user id of the home side, to match the score to the teams (the creator is not always at home). Absent otherwise.

integer | null format: int32
id
required

The tournament id.

integer format: int64
is_private

true when only invited teams may join.

boolean
max_teams
required

Seats. 2 for a 1v1 challenge.

integer format: int32
min_teams
required

Teams needed to start; with fewer at the deadline the tournament is cancelled.

integer format: int32
opponent_badge

1v1 challenge rows of the tournament lists: the opponent’s team badge once an opponent holds the second seat. Absent otherwise.

string | null
opponent_ovr

The opponent’s team OVR, read like creator_ovr, once an opponent holds the second seat. Absent otherwise.

number | null format: double
opponent_ovr_formation

The formation the opponent’s best XI is built in. Absent with opponent_ovr.

string | null
opponent_team_name

1v1 challenge rows of the tournament lists: the opponent’s team name once an opponent holds the second seat. Absent otherwise.

string | null
organizer_only

Tournament detail only: true when the creator runs the tournament without a seat. Absent elsewhere.

boolean | null
ovr_max

The highest best XI OVR a team may have to join, a whole number from 1 to 100. Absent when there is none. While registration is open its creator or an admin can raise it or remove it; it never drops.

integer | null format: int32
ovr_min

The lowest best XI OVR a team may have to join, a whole number from 1 to 100. Absent when there is none. The best XI OVR is the average OVR of the strongest XI a manager can field from the cards they own; it is checked once, when a team joins. While registration is open its creator or an admin can lower it or remove it (POST /api/tournaments/{id}/ovr-range); it never rises.

integer | null format: int32
participant_count

Seats taken. Filled by GET /api/tournaments; null in other answers.

integer | null format: int64
round_interval_minutes
required

Minutes between one match’s kickoff and the next.

integer format: int32
runner_up_user_id

User id of the runner-up, set when the tournament completes; null before.

integer | null format: int32
sc_tournament_id

Id of the tournament on chain (equal to id) for a paid tournament once it is created there; null for a free tournament.

integer | null format: int64
started_at

When registration closed and the draw was made (RFC 3339); null before.

string | null format: date-time
starts_at
required

Kickoff of the first match (RFC 3339).

string format: date-time
status
required

open: registration is open. pending_sc: a paid tournament is being created on chain and cannot be joined yet. active: registration closed and the tournament is under way. completed: finished, podium set. cancelled: too few teams at the deadline or cancelled by its creator. awaiting_payment: a challenge or tournament its creator authorized with POST /api/tournaments/challenges/authorize and has not paid yet; only its creator is ever answered it.

string
target_user_id

Targeted 1v1 challenge: user id of the only opponent who may accept. Given to the creator and the target only; null for everyone else and for any other tournament.

integer | null format: int32
targeted

true for a 1v1 challenge locked to one opponent. Absent otherwise.

boolean
targeted_to_you

true when you are the opponent a targeted 1v1 challenge is locked to. Absent otherwise.

boolean
third_place_user_id

User id of the third-placed team, set when the tournament completes; null before and when no third place is decided.

integer | null format: int32
tier
required

bronze, silver or gold. A Bronze with an entry fee (possible once the competition levels are live) is paid like Silver; one without is free.

string
title
required

Name of the tournament.

string
winner_user_id

User id of the winner, set when the tournament completes; null before.

integer | null format: int32
error

Why the request was refused, in plain words. Present when success is false.

string | null
success
required

true when the request did what it asked. false is a refusal: read error.

boolean
Example generated
{
"code": "example",
"data": {
"away_penalty": 1,
"away_score": 1,
"blocking_window_end": "2026-04-15T12:00:00Z",
"blocking_window_start": "2026-04-15T12:00:00Z",
"cancelled_at": "2026-04-15T12:00:00Z",
"challenge_deadline_minutes": 1,
"completed_at": "2026-04-15T12:00:00Z",
"created_at": "2026-04-15T12:00:00Z",
"creator_badge": "example",
"creator_ovr": 1,
"creator_ovr_formation": "example",
"creator_team_name": "example",
"creator_user_id": 1,
"deadline": "2026-04-15T12:00:00Z",
"decided_by": "example",
"description": "example",
"developer_mode": true,
"distribute_tx_hash": "example",
"entry_fee_foxsy": 1,
"featured": true,
"format": "example",
"has_third_place_match": true,
"home_and_away": true,
"home_penalty": 1,
"home_score": 1,
"home_user_id": 1,
"id": 1,
"is_private": true,
"max_teams": 1,
"min_teams": 1,
"opponent_badge": "example",
"opponent_ovr": 1,
"opponent_ovr_formation": "example",
"opponent_team_name": "example",
"organizer_only": true,
"ovr_max": 1,
"ovr_min": 1,
"participant_count": 1,
"round_interval_minutes": 1,
"runner_up_user_id": 1,
"sc_tournament_id": 1,
"started_at": "2026-04-15T12:00:00Z",
"starts_at": "2026-04-15T12:00:00Z",
"status": "example",
"target_user_id": 1,
"targeted": true,
"targeted_to_you": true,
"third_place_user_id": 1,
"tier": "example",
"title": "example",
"winner_user_id": 1
},
"error": "example",
"success": true
}

No valid session. The body is plain text: Missing Authorization header, Invalid Authorization format, Invalid session token or Session expired or invalid. Sign in again.

Media type text/plain
string
Example
Session expired or invalid