Contents

1. Overview

An HTTP API for reading and updating n01 tournaments, leagues, matches, team orders, and tournament statistics from external systems.

2. Data retrieval APIs (authentication optional)

The retrieval APIs work without Basic authentication (only autopilot/get, autopilot/list and team/player/list?all=1 need Basic authentication as an administrator). When it is supplied, the tournaments and leagues that the authenticated user administers also include admin_id, admin_name, join_pass and scorer_pass (always in tournament/get / league/get; in the list APIs only when requested explicitly with fields=), and the lists include your own private competitions (see 5. Authentication). Wrong credentials are rejected with result: -40. After repeated failures (20 within 10 minutes for the same address and user name) further attempts are refused for a while, even with the correct password.

GET/api/v1/health

Health check. Returns the server status.

GET/api/v1/tournament/list

Returns the list of tournaments. Private and deleted tournaments are excluded. With Basic authentication the private competitions you administer are included as well (use owner=1 to list only the tournaments you administer). Use the common list parameters for filtering, sorting, and paging.

Filterable fieldstdid lgid title t_date status kind softdarts league game_type createTime updateTime
keywordKeyword search on the title (space-separated words are ANDed)
Sortable fieldscreateTime (default, descending) updateTime t_date status title
Default fields returnedtdid lgid createTime updateTime title t_date status kind
Additional fields via fieldsThe above plus softdarts league game_type details image color theme theme_css oom win_lose sd_legs
GET /api/v1/tournament/list?status__in=20,30&sort=createTime&order=desc&count=20

{"result":0, "list":[
  {"tdid":"...", "lgid":"...", "createTime":1700000000, "updateTime":1700000001000,
   "title":"Spring Open", "t_date":1775001600, "status":30, "kind":"darts"},
  ...
]}

GET/api/v1/tournament/get

Returns the full data of a single tournament.

tdidRequired. Tournament ID
entryPass 0 to omit entry_list (included by default)

The response's tournament contains the tournament document (including the bracket table and settings). Non-public items are never included. When you fetch a tournament you administer with Basic authentication, admin_id, admin_name, join_pass and scorer_pass are included as well.

The response also has url, the page that participants and spectators open (https://n01darts.com/n01/tournament/comp.php?id=<tdid>, or https://n01darts.com/n01/league/season.php?id=<tdid> for an event of a league).

{"result":0, "tournament":{...}, "url":"https://n01darts.com/n01/tournament/comp.php?id=t_Ab1c_2345"}

GET/api/v1/tournament/entry/list

Returns the entry list. tdid is required.

Each entry has tpid and name, plus sns_type join startScore c (country) index when set. Non-public items are never returned. With the Basic authentication of an administrator of the tournament each entry also carries pass_set (0 / 1), whether an individual password is set (the password itself is never returned; the entry_list of /api/v1/tournament/get behaves the same).

GET/api/v1/tournament/stats

Returns the tournament statistics. tdid is required.

kind stats_list (default) — per team/player statistics
player_stats_list — per individual player statistics (team events)
player_high_out — high outs
player_high_in — high ins
player_best_leg — best legs
rr_stats_list — player statistics per round robin block
lg_stats_list — player statistics per league division

The statistics are identical to the ones shown on the stats pages. The data is returned in the response's stats.

GET/api/v1/league/list

Returns the list of leagues. Private and deleted leagues are excluded. With Basic authentication the private leagues you administer are included as well (use owner=1 to list only the leagues you administer).

Filterable fieldslgid title status createTime updateTime
keywordKeyword search on the title
Sortable fieldscreateTime (default, descending) updateTime title status
Default fields returnedlgid createTime updateTime title status
Additional fields via fieldsThe above plus details image theme theme_css ad

GET/api/v1/league/get

Returns the full data of a single league. lgid is required. As with tournaments, non-public items are never included. The response also has url, the league portal page (https://n01darts.com/n01/league/portal.php?lgid=<lgid>).

{"result":0, "league":{...}, "url":"https://n01darts.com/n01/league/portal.php?lgid=lg_Ab1c_2345"}

GET/api/v1/league/entry/list

Returns the league entry list. lgid is required. Each entry has lpid and name, plus c and sns_type when set.

GET/api/v1/league/tournament/list

Returns the list of events (tournaments) that belong to a league. lgid is required. The parameters are the same as /api/v1/tournament/list, except owner and admin_id, which do not apply here (they are ignored). Like the league portal, private events of the league are included (deleted ones are excluded).

GET/api/v1/match/list

Returns the list of matches. Private and deleted matches are excluded. By default the archive is searched (all matches, including ones in progress, are kept in sync there).

Filterable fieldsmid tdid tmid schid scid match_type endMatch endSchedule relayMode title startTime
playerPartial, case-insensitive match on player names. Must be combined with tdid (-51 without it)
livePass 1 to search only matches in progress (not yet moved to the archive)
Sortable fieldsstartTime (default, descending) updateTime
Default fields returnedmid tdid tmid schid scid match_type title startTime endMatch statsData
Additional fields via fieldsThe above plus endSchedule relayMode settings currentSet currentLeg updateTime

match_type is "01" or "cricket". Matches without it are 01 matches.

GET/api/v1/match/get

Returns the full data of a single match, including per-leg scores. mid is required. The archive is searched first; when the match is not there, the matches in progress are searched. Deleted matches are not returned. A private match (private = 1) is returned only to the administrator of the tournament it belongs to (Basic authentication); otherwise -1 is returned.

Non-public items are never included. SNS-related IDs inside statsData are masked to "1" (presence only).

GET/api/v1/team/order/list

Returns the team orders of a team event.

tdidRequired. Tournament ID
tmid tpid schidOptional filters

Each element has tmid tpid schid and fix (whether the order is fixed). When an order has been submitted it also has order (the lineup; oid opid oname are complemented from the team player list), and res when a result has been entered.

GET/api/v1/team/player/list

Returns the team players. tdid is required, tpid is optional (all teams when omitted). Deleted players are excluded. Each player has tpid oid opid oname, plus index when it is set (players without an index come last).

With all=1 the deleted players are returned as well, each with delete (this needs Basic authentication as an administrator of the tournament).

GET/api/v1/tournament/standings

Returns the standings of the league (lg) and round robin (rr) groups. tdid is required. The ranks are computed with the same rules as the pages (points, Buchholz, win/loss difference, leg difference and head-to-head). A tournament with neither a league nor a round robin format returns result: -51.

{"result":0, "tdid":"...", "groups":[
  {"kind":"lg", "index":0, "title":"Division 1", "players":[
    {"tpid":"aaaa", "name":"Player One", "rank":1, "p":3, "w":3, "d":0, "l":0, "diff":6, "diff_l":0, "pts":6, "bh":4, "byes":0},
    ...
  ]}
]}

players is ordered by rank. Players who have not played yet have rank 0 and come last. p played / w d l won, drawn, lost / diff leg difference (set difference in a set format) / diff_l leg difference of a set format / pts points / bh Buchholz (swiss, when enabled) / byes number of byes. The points include the manual bonus points of the management screen (lg_pts, rr_pts for a round robin with the point system), the bonus points of a result (add) and the points per game of a team event (pt), like the standings of the pages. A round robin without the point system is ranked by win lose leg_win leg_lose and has no pts.

GET/api/v1/tournament/end_group

Returns whether every match of each round robin block (rr_<index>) and league division (lg_<index>) has finished (1 = finished, 0 = not yet). Use it before assigning the qualifiers to the final bracket.

{"result":0, "tdid":"...", "groups":{"rr_0":1, "rr_1":0}}

GET/api/v1/league/schedule/get

Returns the fixtures (match cards) of the league format. tdid is required, div (division index) is optional (without it one array per division is returned).

{"result":0, "tdid":"...", "swiss":0, "schedule":[
  [{"p":["aaaa","bbbb"], "lsid":"ab3f", "t":""}, {"p":["cccc","dddd"], "lsid":"k9x2", "t":"", "r":1}],
  []
]}
FieldMeaning
pThe two tpid of the card. "" is an empty slot, "empty" a bye
lsidCard ID (4 characters). The result is stored in lg_result["<div>_<lsid>"]
tCard title
rSwiss round number (1-based)

For a swiss league swiss is 1 and rounds carries, per division, the current round (round), the total number of rounds (total), the unassigned slots of the current round (blank) and the player count (members).

GET/api/v1/league/stats

Returns the statistics of a league (all its events). lgid is required. kind is stats_list (default), player_stats_list, rank_list or t_list; the same JSON as the league statistics page is returned in stats.

GET/api/v1/autopilot/get

Returns the autopilot (automatic board assignment) settings and the status written by the autopilot server. tdid is required and the Basic authentication of an administrator of the tournament is needed.

{"result":0, "tdid":"...",
 "config":{"tdid":"...", "lgid":"...", "group":"...", "name_control":0, "name_mode":"auto", "priority":0, "hold_robin":0,
           "types":{"t":{"badge_number":"1-10", "break_time":0, "round":0, "enable":1}, "s2":{...}, "dw":{...}, "dl":{...}},
           "remove_old_badge":1, "set_referee":0, "referee_type":"same_board", "updateTime":1700000000000},
 "status":{"time":1700000000000, "error":"", "held":{...}}}

config is null when nothing has been set. status.held lists the matches the server did not assign a board to (with the reason: opponent undecided, waiting for a board, player busy or on a break), the same list as the settings page.

GET/api/v1/autopilot/list

Returns the autopilot settings and status of every event of a league. lgid is required and the Basic authentication of an administrator of the league is needed. Each item has tdid title status (tournament state) and config / status as above.

3. Common list parameters

The list APIs (.../list) accept the following query parameters so that many conditions can be combined freely.

ParameterMeaningExample
<field>=<value>Equalsstatus=30
<field>__ne=<value>Not equalmatch_type__ne=cricket
<field>__gt / __gte=<value>Greater than / or equalstartTime__gte=1700000000
<field>__lt / __lte=<value>Less than / or equalupdateTime__lt=1700000000000
<field>__in=<v,v,...>Matches any of the valuesstatus__in=20,30
<field>__nin=<v,v,...>Matches none of the valuesstatus__nin=40
<field>__exists=0|1Whether the field existslgid__exists=1
<field>__regex=<text>Partial match, case-insensitive (string fields only)title__regex=open
keyword=<word word...>Keyword search on the title (tournament / league). Up to 8 words of 100 characters eachkeyword=summer%20cup
owner=1Only the tournaments / leagues you administer (tournament / league). Requires Basic authenticationowner=1
admin_id=<id>Filter by administrator (tournament / league). Requires Basic authentication; only your own admin_id is accepted (admin_id=me means your own admin_id)admin_id=twid:12345
player=<name>Partial match on player names (match). 2 to 100 characters. tdid is requiredtdid=XXXX&player=alice
sort=<field>Sort fieldsort=startTime
order=asc|descSort order (default desc)order=asc
skip=<n>Number of items to skip (up to 100000)skip=100
count=<n>Number of items to return (capped; default/cap is 100)count=50
fields=<field,...>Select the fields to return (public fields; with Basic authentication admin_id admin_name join_pass scorer_pass may be selected too for the competitions you administer)fields=tdid,title,status
Only the fields listed for each endpoint can be used for filtering, sorting, and fields. An unknown sort or fields name, an unknown __ operator, or a value that does not fit the field type is rejected with result: -51; a filter parameter whose field is not listed is ignored (it does not narrow the result), so check the spelling of your filters. The time fields createTime, t_date and startTime are seconds; updateTime is milliseconds. Multiple conditions can be combined on the same field (e.g. startTime__gte=...&startTime__lt=...).

4. Data structures

The JSON returned by the API mirrors n01's internal data. This chapter describes the main fields (fields that are not listed are used internally by the system). The update APIs take the same structures.

4.1 Identifiers

IDDescription
tdidTournament ID, issued when the tournament is created and contained in its URL (e.g. t_Ab1c_2345)
lgidLeague ID (e.g. lg_Ab1c_2345). Events that belong to a league carry it
The web page of a competition cannot be derived from its ID alone (a tournament and an event of a league open on different pages). tournament/get, tournament/create, league/get and league/create return url, the page participants and spectators open, next to the document. Use it instead of building an address from the ID.
tpidTournament player ID: a 4 character ID for one entry
lpidLeague player ID
tmidTournament match ID, formatted as <tdid>_<ttype>_<round>_<tpid>_<vsTpid> (for a league: <tdid>_lg_<division>_<round>_<tpid>_<vsTpid>). It identifies one fixture
midMatch ID: the game data of one set
scidGroups the sets of one game in a set-based match
schidSchedule ID: one game inside a fixture that has several games (team battles etc.)
oidTeam member ID (unique inside a tournament). Older data may use a number
opidTeam member number given by the organizer

4.2 Competition types (ttype)

A tournament can hold several competition formats at the same time, each with its own settings, bracket and results. The format is identified by its type, which forms the {ttype}_ prefix of those fields.

ttypeDescription
lgLeague
rrRound robin
tSingle elimination 1
t3Third place match of single elimination 1
s2Single elimination 2
s2_3Third place match of single elimination 2
dwWinners side of a double elimination
dlLosers side of a double elimination
mSingle matches (knockout games)

4.3 Tournament state (status)

statusDescription
10Preparing
20Accepting entries
25Building the bracket
30In progress
40Finished

4.4 Tournament (tournament)

The main fields of the document returned by /api/v1/tournament/get.

FieldTypeDescription
tdidstringTournament ID
lgidstringID of the league it belongs to (absent for a stand-alone tournament)
leaguenumber1: treated as an event of a league and hidden from the tournament list (the list page of the tournament area). Set to 1 when created under a league. It does not affect the filtering of /api/v1/tournament/list
createTimenumberCreation time (UNIX time in seconds)
updateTimenumberUpdate time (UNIX time in milliseconds)
statusnumberTournament state (4.3)
titlestringTournament title
t_datenumberCompetition date (UNIX time in seconds), 0 when not set
s_datenumberDate used for sorting (UNIX time in seconds). Set on creation from t_date (the creation time when t_date is not set). Updating t_date does not change it, so send both when you change the date
detailsstringDescription of the competition
imagestringURL of the title image
colorstringBackground color (used with the standard theme only)
theme theme_cssstringTheme of the competition and the URL of a custom theme CSS
langstringDisplay language ("" follows the browser language)
kindstringKind of competition (darts, softdarts, billiards, tennis, table_tennis, football, common, or a free name)
softdartsnumber1: soft-tip darts
game_typenumberBit flags of how players take part. 1: n01 Live (local match) / 2: n01 Online / 4: submit results
privatenumber1: hide from the public list
adnumber1: show advertisements
chatnumber1: enable the chat
show_avgnumber1: show averages
dynamic_avgnumber1: show the dynamic average
auto_completenumber1: finish the tournament automatically
confirm_startnumber1: players must confirm the opponent before a game
select_firstnumber1: choose who throws first at the start (n01 Live only)
lfnumber1: the loser of the previous leg throws first in the next one
win_losenumber1: show the result as win/lose marks (only for a single point match)
sd_legsnumber1: label Sets as Legs
individual_passnumber1: ask for a personal password on the first participation
hide_snsnumber1: do not use SNS entries
common_joinnumber1: do not pick a player when joining (anyone can enter scores)
show_entry_nonumber1: show numbers in the entry list
team_gamesnumber1: team battle
name_sepstringSeparator in a name (where to break the line, for doubles etc.)
oomobjectRanking (order of merit) settings
entry_listarrayEntry list (4.6), added by tournament/get only
{ttype}_settingobjectSettings of that format (4.5)
{ttype}_tablearrayBracket (4.5)
{ttype}_resultarrayResults (4.5)
{ttype}_titlearrayRound titles
{ttype}_initarrayGuide (the initial bracket)
admin_id admin_name
join_pass scorer_pass
string Administrator id and organizer name, join password and scorer password. Returned only when you fetch a competition you administer with Basic authentication (5. Authentication)

4.5 Brackets and results

Each format keeps its bracket and results in its own fields. Only the formats whose {ttype}_setting is enabled (lg_setting.league, rr_setting.round_robin, t_setting.tournament, m_setting.matchs and so on set to 1) are used.

FieldStructure
t_table s2_table
dw_table dl_table
One array per round, each holding tpid values. The first round is [0], the second [1]. A slot that is not decided yet is an empty string
rr_tableOne array per group, each holding the tpid values of that group
lg_tableOne array per division, each holding the tpid values of that division. A bye opponent is written as "empty"
t_result s2_result
dw_result dl_result rr_result
One entry per round (per group for a round robin). Each is an object keyed by tpid, holding the result keyed by the opponent's tpid
lg_resultAn object keyed by "<division>_<lsid>" (e.g. "0_ab3f"; lsid is the 4-character ID of the match card). Below that the structure is the same as the other formats
rr_rank lg_rankManually assigned ranks

A result ({ttype}_result[round][tpid][vsTpid]) has the following shape.

FieldDescription
rResult: the number of legs in a leg-based game, the number of sets in a set-based game
lNumber of legs (set-based games only)
aAverage
t100+
t4140+
t8180's
hHigh out
bBest leg
a_bSecond legs
w_bBreak legs
The fixtures of a league format are kept outside the bracket fields and are not part of the tournament document; read and write them with /api/v1/league/schedule/get / update / generate. The Swiss system settings are lg_setting.swiss, swiss_rounds and swiss_bh.

4.6 Entries

The shape of /api/v1/tournament/entry/list and of entry_list in tournament/get.

FieldTypeDescription
tpidstringTournament player ID
namestringPlayer name (team name in a team battle)
cstringCountry code
indexnumberSort order
joinnumberParticipation state (0-9; 1 = has joined). Absent when it is 0 or not set
startScorenumberHandicap (starting score). Absent when not set
sns_typestringLinked SNS (t: Twitter / f: Facebook / g: Google). Absent when not linked

4.7 League (league)

A league groups several tournaments (events). Its events are listed with /api/v1/league/tournament/list.

FieldTypeDescription
lgidstringLeague ID
title detailsstringTitle and description
show_detailsnumber1: show the description on the portal
createTime updateTimenumberCreation time (seconds) and update time (milliseconds)
image color
theme theme_css lang
string Same as a tournament. theme and lang are also the defaults for new events
sort sort_orderstring / numberOrder of the events (date / name / manual) and ascending (1) / descending (-1)
private adnumberSame as a tournament
show_countnumberNumber of events per page in the event list of the portal and the league settings (10 when missing or 0)

A league entry (/api/v1/league/entry/list) has lpid, name, c and sns_type.

4.8 Match (match)

A match is the game data of one set. Matches in progress live in match and every match including the finished ones in match_archive; /api/v1/match/get looks in the archive first and falls back to the matches in progress (it has no live parameter; live=1 exists on /api/v1/match/list only).

FieldTypeDescription
midstringMatch ID
match_typestring"01" or "cricket". A match without this field is 01
tdid lgidstringTournament ID and league ID
tmid ttype round t_nostring / number Fixture ID, competition type, round (0 based) and the position in the bracket (1 based)
scid schidstringThe ID grouping the sets and the ID of the game inside the schedule
title orgTitlestringTitle with and without the subtitle
startTimenumberStart time (UNIX time in seconds)
updateTimenumberUpdate time (UNIX time in milliseconds)
startScorenumberStarting score (01 only)
roundLimit maxRoundnumber0/1: whether rounds are limited, and the limit
limitSet limitLegnumberNumber of sets and legs to win
currentSet currentLegnumberCurrent set / leg (0 based)
drawModenumber0: no draw / 1: draws allowed
endMatchnumber0: this set is not finished / 1: finished
endSchedulenumber1 once every game is finished. Absent otherwise
privatenumber1: hide from the history list
legDataarrayPer-leg data
statsDataarrayPer-player stats (the left player is [0])

Each element of legData (for 01) has the following shape.

FieldTypeDescription
timenumberStart time of the leg (milliseconds)
firstnumber0: the left player throws first / 1: the right player throws first
endFlagnumber0: the leg is not finished / 1: finished
winnernumber0: the left player won / 1: the right player won
middleForDiddlenumber1: the leg was decided by a middle for diddle (closest to the bull); the winner is in winner. The leg was not finished by throwing, so the statistics do not count its darts and scores. Used when the round limit is reached, but available at any time
playerDataarrayOne array per player, each holding {"score": scored, "left": remaining} per round. On a finish the score is negative and tells the dart (-1: first / -2: second / -3: third)
"playerData": [
  [ {"score":0,"left":501}, {"score":180,"left":321}, {"score":180,"left":141}, {"score":-3,"left":0} ],
  [ {"score":0,"left":501}, {"score":100,"left":401} ]
]

Each element of statsData has the following shape.

FieldTypeDescription
namestringPlayer name
pidstringPlayer ID (internal to n01)
tpidstringTournament player ID
winSets winLegsnumberSets won (as of the start of this set) and legs won
allScore allDartsnumberTotal score and darts thrown (used for the average)
orderarrayTeam battle order (4.9)
The SNS ids (tid, fid, gid) are masked to "1", which only tells whether they are set. When statsData is sent to an update API, those items keep their server-side values.

For Cricket (match_type is "cricket") each leg holds turns (one entry per turn) instead of playerData. A turn is {"p": player, "r": round, "h": [[number index, marks], ...]}, where the number index is the position in [20, 19, 18, 17, 16, 15, BULL]. statsData holds allMarks (total marks) instead of allScore.

4.9 Team members and orders

In a team battle (team_games is 1) an entry (tpid) is a team, and its members and the order they play in each fixture are kept separately.

FieldDescription
tpidID of the team (the entry)
oidMember ID, unique inside the tournament
opidMember number given by the organizer
onameMember name
indexSort order

An order (/api/v1/team/order/list) is one entry per (tmid, tpid, schid), and order holds the members playing that game in their playing order (on retrieval oid, opid and oname are filled in; a member that no longer exists comes back as empty strings). fix tells whether the order is confirmed (1), and res is the result of that game.

4.10 Doubles

Doubles can be set up in two ways. Normally the first one (one entry carrying the names of both players) is enough. When you want statistics per player (average, high finish, etc.), the second one, building the pairs as teams with a schedule, is the effective way.

WayEntryStatistics
Both names in one entry (normal)One pair = one entry. Write the name like Smith / Jones; with name_sep set to "/" the name breaks the line after the separatorPer pair
Teams with a schedule and automatic ordersOne pair = one team. Register the two players as members of the teamPer pair and per player

Settings for the second way:

{
  "team_games": 1,
  "name_sep": "/",
  "t_setting": {
    "tournament": 1, "t_player_count": 16,
    "limit": 3, "setOrder": 1, "autoOrder": 1, "exitResult": 1,
    "schedule": [
      {"subTitle": "Doubles", "startScore": 501, "match_type": "01", "roundLimit": 1, "maxRound": 15, "overkill": 0,
       "limit_leg_count": 2, "drawMode": 0, "num_part": 2, "group": 0, "pt": 0, "ignore_avg": 0}
    ]
  }
}

(The other fields of t_setting are omitted. {ttype}_setting is replaced as a whole, so send every field it needs.)

5. Authentication

The API uses HTTP Basic authentication. The user and the password are issued automatically when you subscribe to the API (see Subscribing to the API).

Authorization: Basic <Base64 of user:pass>

On authentication failure the API returns HTTP 401 with result: -40.

Every API user has an admin_id (an n01 administrator id). You can create, update and delete only the tournaments and leagues that are administered by that id, and the data below them. Otherwise the API returns HTTP 403 with result: -41.

The APIs that use Basic authentication (creating, updating and deleting data, and authenticated retrieval) require an API subscription. Without a subscription, or once it has expired, the API returns HTTP 402 with result: -42. The retrieval APIs without authentication (public data) can be used without a subscription (so can the password change /api/v1/user/password).

What an API user can do depends on its admin_id:

admin_idWhat it can do
SetRead (including the administration items), create, update and delete the tournaments and leagues of that administrator (a subscription is required)
Not setRetrieval APIs only (public data)

Subscribing to the API

You subscribe from the payment page of a tournament.

  1. Open the administration screen (Setting) of a tournament.
  2. Follow the "About pricing." link to the payment page.
  3. Select the "API" tab and buy the monthly or the yearly plan with PayPal.

You can subscribe the same way from a league ("About pricing." → "API" tab). Either way there is one subscription per n01 administrator id, not one per competition. It is separate from the subscription that raises the number of players and from the pay per event payment, and the API plans do not raise the number of players of a competition.

One API user is issued automatically per administrator when you subscribe, and the user name and the expiry date are shown on the same "API" tab. The password is shown only once right after it is issued, so keep a copy of it. If you lose it, you can issue a new one with "Reissue password" on the same page (the previous password stops working).

You cancel from the "Subscription list page" on the payment page. Even if you cancel, you can continue to use the API until the expiry date, after which it stops working.

OAuth 2.1 (for MCP clients)

For MCP clients that only offer OAuth or no authentication, such as the custom connectors of claude.ai, the API server is also an OAuth 2.1 authorization server. It supports the standard flow from client registration to token issuance (dynamic client registration, authorization code with PKCE, refresh tokens), so an MCP client discovers it automatically once you register https://push.n01darts.com/api/v1/mcp.

EndpointDescription
GET /.well-known/oauth-authorization-serverAuthorization server metadata (RFC 8414)
GET /.well-known/oauth-protected-resource/api/v1/mcpProtected resource metadata (RFC 9728)
POST /api/v1/oauth/registerClient registration (RFC 7591). redirect_uris must be https (http only for localhost)
GET /api/v1/oauth/authorizeAuthorization (response_type=code, PKCE S256 is required)
POST /api/v1/oauth/tokenToken issuance (authorization_code / refresh_token)
POST /api/v1/oauth/revokeToken revocation (RFC 7009)

POST/api/v1/user/password

Changes your own password. Authenticate with the current password, then send the current and the new password as JSON. The new password must be 8 to 100 characters and different from the current one.

{"password": "current password", "new_password": "new password"}

There is a page for it as well: Change password. Control characters are not allowed in the new password (result: -3).

6. Create / update / delete APIs (Basic authentication)

POST a JSON body (Content-Type: application/json). All public fields returned by the retrieval APIs can be updated, including nested structures (brackets, settings, etc.). Non-public items, IDs, the delete flag and createTime / updateTime cannot be updated. If the request contains even one field that cannot be updated, or an invalid value, the whole request is rejected with result: -3 and nothing is updated.

On a successful update, updateTime is updated automatically. Tournament updates also trigger an update notification so that spectator pages refresh in real time (when the tournament belongs to a league, the league's updateTime is updated as well).
Tournaments and leagues are backed up right before an update or a delete, exactly as the administration pages do (a tournament backup also holds the entries, the bracket, and the team members and orders). The 10 most recent backups are kept and can be restored by the server administrator.

POST/api/v1/tournament/create

Creates a tournament and returns the newly assigned tdid together with url, the page participants and spectators open. Show url to the user; it is the address to share. set accepts the same fields as /api/v1/tournament/update (omitted items get their default value), and entry_list registers the entries at the same time. title (tournament name) and join_pass (join password) are required; a request without them or with an empty value is refused with result: -3. On creation the title is trimmed and, when it is longer than 60 characters, stored cut to 60 characters followed by ... (the same rule as the administration screen; tournament/update accepts the full 200 characters).

{
  "set": {
    "title": "Autumn Open",
    "status": 20,
    "t_date": 1800000000,
    "join_pass": "pass1234",
    "rr_setting": {"round_robin": 1, "robin_count": 1, "robin_player_count": 8}
  },
  "entry_list": [
    {"name": "Player One", "c": "JP", "index": 1},
    {"name": "Player Two", "c": "JP", "index": 2}
  ]
}
{"result":0, "tdid":"t_Ab1c_2345", "added":[{"tpid":"Xy3f", "name":"Player One"}, ...],
 "url":"https://n01darts.com/n01/tournament/comp.php?id=t_Ab1c_2345"}
Requiredtitle join_pass
Main defaultsstatus=10 (preparing) kind=darts ad=1 chat=1 show_avg=1 auto_complete=1 game_type=1 private=0 scorer_pass=""
Set by the servertdid admin_id admin_name createTime updateTime s_date pass_hash scorer_pass_hash max_user

admin_name (the organizer name shown on the pages) is copied from the most recent tournament or league of the same administrator; when there is none, the API user name is used. Change it afterwards with tournament/update if needed. Administrators the site operator has exempted from payment get the tournament without max_user (no player limit), and administrators exempted from advertisements get ad 0, exactly as in the administration screen. Creating with status 30 (in progress) is subject to the player limit described under /api/v1/tournament/update; when it is exceeded the created data is removed again and result: -5 is returned (result: -6 when the limit could not be checked). A tournament cannot be created with status 30 while the bracket of an enabled format is empty (result: -3). The format exclusions (league and round robin, double and single elimination cannot be enabled together) and the automatic third place table are the same as for /api/v1/tournament/update.

With lgid the tournament is created as an event of that league (you must administer the league). The administrator information is inherited from the league and league becomes 1. An event of a league opens on the league area's page, so url becomes https://n01darts.com/n01/league/season.php?id=<tdid>. Only the enabled ones of lg_setting / rr_setting / t_setting / s2_setting / d_setting / m_setting are stored, together with their empty brackets.

The response also carries the updateTime of the created document, so that it can be passed as expect_update_time to a following tournament/update (league/create behaves the same).

POST/api/v1/tournament/update

Updates a tournament. All public fields returned by /api/v1/tournament/get can be specified, including the bracket (table) and the various settings. tdid and entry_list cannot be updated (use /api/v1/tournament/entry/update for entries). The administrator information (admin_id), max_user, the delete flag and the items only the site operator can change (ranking and special progression options) cannot be updated either. An empty set is refused with result: -3. The advertisement flag (ad) is decided by the payment state, so it cannot be given on creation nor on update.

Setting status to 30 (in progress) is subject to the same player limit as the administration screen: when the entries of the tournament (together with the organizer's other tournaments in progress) exceed the free players plus the purchased players, the request is refused with result: -5 (HTTP 402) and nothing is written (the check is skipped when the tournament is already in progress, or when it has no player limit because the organizer is exempt from payment; result: -6 when the payment server could not be reached). The organizer can buy players or a subscription on the pricing page of the administration screen. Other status changes are not affected. To move the tournament into another league by changing lgid, you must administer that league. When join_pass / scorer_pass are updated, the server recalculates the pass_hash / scorer_pass_hash used to check them. title and join_pass are required items, so an update that empties them is refused with result: -3.

An update through this API invalidates the administration screens that are open for the tournament, just like saving it from another screen does: their next save fails with "The data has been updated" and the screen has to be reloaded. Conversely, to avoid overwriting a change made from the administration screen (or by another API client) between your read and your update, send the updateTime returned by /api/v1/tournament/get as expect_update_time (UNIX milliseconds). When the tournament has been updated since, the request is refused with result: -7 (HTTP 409) and nothing is written; read the tournament again and retry (a non-integer expect_update_time is refused with result: -51).

{
  "tdid": "tournament ID",
  "expect_update_time": 1767225600000,
  "set": {
    "title": "Spring Open 2026",
    "status": 30,
    "theme": "dark"
  }
}

The values of the following fields are validated.

FieldValue
titleString (up to 200 characters, cannot be empty)
detailsString (up to 10000 characters)
t_date s_dateCompetition date / sort date (integer, UNIX time in seconds, 0 when not set). Changing t_date does not update s_date
lg_setting.swiss swiss_bh swiss_roundsSwiss system settings. swiss / swiss_bh are 0 / 1, swiss_rounds an integer 0-1023 (the rest of the settings is not validated)
status10=preparing / 20=accepting entries / 25=building the bracket / 30=in progress / 40=finished (other values are rejected). An update to 30 is refused with -3 when the bracket of an enabled format (lg_table / rr_table / t_table / s2_table / dw_table / m_table) is missing or empty (the same as "the bracket has not been created" on the administration screen; a bracket sent in the same request counts). A tournament already at 30 is not checked
private0 / 1 (hide from the public list)
entry_lock0 / 1 (lock entries)
order_empty_error0 / 1
colorBackground color as a CSS color value (#rrggbb, #rgb, a color name such as white, or rgb() / rgba() / hsl() / hsla(); up to 50 characters, "" to clear)
imageString (image URL, up to 2000 characters)
theme"" / dark / scifi / neon / orange / custom
theme_cssURL of a custom theme CSS (must start with https:// or /)
langDisplay language (""=automatic, or a language code in /n01/lang/ such as ja or en)
kindKind of competition (up to 30 characters), e.g. darts softdarts billiards
lgidID of the league it belongs to (up to 100 characters)
game_typeInteger (bit flags, 0-7). 1=n01 Live / 2=n01 Online / 4=submit results
league softdarts chat show_avg auto_complete confirm_start dynamic_avg lf individual_pass hide_sns common_join show_entry_no team_games select_first win_lose0 / 1
sd_legsInteger (0-99)
name_sepString (up to 10 characters)
admin_nameOrganizer name (up to 200 characters)
join_pass scorer_passJoin password / scorer password (up to 100 characters; join_pass cannot be empty)
lg_setting rr_setting t_setting s2_setting d_setting m_setting When the block is enabled (league / round_robin / tournament / matchs is 1) its size is validated: robin_count (1 or more) and robin_player_count (2 or more) with a product of at most 1024, t_player_count (a power of two from 2 to 1024; 4 or more for d_setting), match_count (1 to 512). The league format (lg_setting.league) and round robin (rr_setting.round_robin), and double elimination (d_setting.tournament) and single elimination (t_setting.tournament / s2_setting.tournament) cannot be enabled at the same time (the same exclusion as the administration screen; the stored settings are taken into account, so send the setting you disable in the same request when switching). When t_setting.t3 / s2_setting.t3 is 1 and t3_table / s2_3_table is missing or empty, the server creates the empty third place table ([["",""],[""]]). The game id schid of each row of schedule (and of the schedule inside each game_setting element) is assigned by the server when missing or empty (4 characters of 0-9a-z; existing values are kept). A duplicate within one schedule, or a value that is not a string, is -3
t_table t3_table s2_table s2_3_table dw_table dl_table m_table rr_table lg_table Must be arrays
t_result t3_result s2_result s2_3_result dw_result dl_result m_result rr_result lg_result rr_rank lg_rank Must be objects or arrays
Other fields Keys must not contain $ or . and must not be JavaScript reserved names (__proto__, constructor, ...); nesting is limited to 64 levels. Any violation rejects the whole request with -3
When updating structured fields such as the bracket, it is recommended to read the current value with the retrieval API, change only what you need, and send it back (each field is replaced as a whole). The updated fields also reach the participant and spectator pages that have the tournament open, without a reload (brackets, results, settings, badges, announcements, memos, final assignment, entries; the same notification as a save from the administration screen).

Settings and brackets: what to take care of (things that affect the progress of the tournament)

The administration screen prevents the following inconsistencies in its UI; the API does not check them. Getting them wrong shows up as matches that cannot be started or finished, or as a tournament that never completes.

Give the brackets of an enabled format the same shape the administration screen creates: t_table / s2_table have log2(t_player_count) + 1 rows whose length halves each round, dw_table has log2(t_player_count) + 3 rows, dl_table has 2 × (log2(t_player_count) − 1) rows, m_table has match_count rows of [left, right], rr_table / lg_table have robin_count rows of robin_player_count slots. A different shape shows up as winners that are not written into the next round, Losers players that disappear, or a tournament that never completes (the API does not check the shape).

Changing lgid or private also updates lgid / private of the matches of the tournament (live and archived), like linking a season on the management screen.

POST/api/v1/tournament/delete

Deletes a tournament (a soft delete that sets the delete flag and removes the link to its league). After that it is no longer visible from the retrieval APIs.

{"tdid": "tournament ID"}

POST/api/v1/tournament/entry/update

Adds, updates, and removes tournament entries. add / update / remove are all optional; specify only what you need (result: -51 when all three are empty). remove deletes the entries for good (unlike the remove of team players it cannot be undone; the state before the change is kept in the backup).

{
  "tdid": "tournament ID",
  "add": [
    {"name": "New Player", "c": "JP", "index": 10}
  ],
  "update": [
    {"tpid": "aaaa", "name": "Renamed Player", "join": 1}
  ],
  "remove": ["bbbb"]
}

All public entry fields can be specified (tdid, tpid, and SNS-related identification cannot be updated). The values of the following fields are validated.

FieldValue
nameDisplay name (leading/trailing spaces and control characters are removed; longer than 60 characters is stored cut to 60 characters plus ...; longer than 200 characters is rejected with result: -3). Required when adding
cCountry code (up to 10 characters)
snameSub name (up to 100 characters; not returned by the retrieval APIs)
joinInteger (0-9). Participation state
indexInteger (0-100000). Sort order
startScoreInteger (0-100000). Handicap
passIndividual password (string, up to 100 characters). Stored with the same rule as the join page (trimmed and lower-cased before hashing); the password itself is not stored. "" clears it (same as "clear password" on the management screen)
release_sns1 releases the SNS link of the entry (same as "release SNS" on the management screen; sns_id, sns_type and the SNS-derived sname are kept aside so that the link can be restored)

Added entries get a newly assigned tpid, returned in the response's added. update targets an entry by its tpid. The response's updated / removed are the numbers of entries actually processed.

{"result":0, "added":[{"tpid":"Xy3f", "name":"New Player"}], "updated":1, "removed":1}

POST/api/v1/league/create

Creates a league and returns the newly assigned lgid together with url, the league portal page. set accepts the same fields as /api/v1/league/update, and entry_list registers the entries at the same time. title (league name) is required; a request without it or with an empty value is refused with result: -3.

{
  "set": {"title": "Winter League", "details": "season 3"},
  "entry_list": [{"name": "League Player", "c": "JP"}]
}
{"result":0, "lgid":"lg_Ab1c_2345", "added":[{"lpid":"Xy3f", "name":"League Player"}],
 "url":"https://n01darts.com/n01/league/portal.php?lgid=lg_Ab1c_2345"}
Requiredtitle
Main defaultsad=1 private=0 sort=date sort_order=-1
Set by the serverlgid admin_id admin_name createTime updateTime

admin_name is copied from the most recent tournament or league of the same administrator; when there is none, the API user name is used.

POST/api/v1/league/update

Updates a league. All public fields returned by /api/v1/league/get can be specified (lgid, entry_list, createTime, updateTime, the administrator information (admin_id), the advertisement flag (ad) and the items only the site operator can change cannot be updated). title is a required item, so an update that empties it is refused with result: -3. Like /api/v1/tournament/update, the update invalidates the open administration screens of the league, and expect_update_time (the updateTime returned by /api/v1/league/get) refuses the update with result: -7 when the league has been updated in between.

{
  "lgid": "league ID",
  "expect_update_time": 1767225600000,
  "set": {"title": "Main League 2026"}
}

The values of the following fields are validated.

FieldValue
titleString (up to 200 characters, cannot be empty)
detailsString (up to 10000 characters)
show_details0 / 1 (show the description on the portal)
imageString (image URL, up to 2000 characters)
colorBackground color as a CSS color value (same as a tournament)
private0 / 1 (hide from the public list)
show_countInteger (0-10000, number of events per page; 0 means the default 10)
statusInteger (0-99)
theme"" / dark / scifi / neon / orange / custom
theme_cssURL of a custom theme CSS (must start with https:// or /)
langDefault display language for new events (""=automatic)
sortOrder of the events (date / name / manual)
sort_order1 (ascending) / -1 (descending)
admin_nameOrganizer name (up to 200 characters)
join_pass scorer_passJoin password / scorer password (up to 100 characters)

POST/api/v1/league/entry/update

Adds, updates, and removes league entries. add / update / remove are all optional. It works like the tournament entry update, but entries are addressed by lpid.

{
  "lgid": "league ID",
  "add": [{"name": "New Player", "c": "JP"}],
  "update": [{"lpid": "aaaa", "name": "Renamed Player"}],
  "remove": ["bbbb"]
}

All public entry fields can be specified (lgid, lpid, and SNS-related identification cannot be updated). The validated fields are name (required when adding), c, sname and index.

{"result":0, "added":[{"lpid":"Xy3f", "name":"New Player"}], "updated":1, "removed":1}

POST/api/v1/league/delete

Deletes a league (a soft delete). When the league still has events (tournaments), the request is rejected with result: -3; delete those events or unlink them from the league first.

{"lgid": "league ID"}

POST/api/v1/match/create

Creates the match data (the per-leg scores) of a finished match, e.g. to import matches scored outside n01 or old records. The match is stored in the archive (shown in the history and counted in the statistics) and can be read with /api/v1/match/get / /api/v1/match/list. Only the administrator of the tournament (tdid) can create matches.

set takes the fields that /api/v1/match/get returns. statsData (2 players, each with the tpid of an entry) and legData (the array of legs, same structure as the retrieval API) are required; ttype / round / t_no (the position in the bracket; tmid is derived from ttype, round and the two tpid when omitted), startTime (UNIX seconds, default now), match_type (01 / cricket), startScore, limitLeg / limitSet, scid / currentSet (in the set format one set is one match document, grouped by the same scid) and title are optional. In statsData, name defaults to the entry name and winLegs / allScore / allDarts are computed from legData (01) when omitted (the SNS link fields are left empty).

{
  "tdid": "tournament ID",
  "set": {
    "ttype": "rr", "round": 0, "startTime": 1105335600,
    "startScore": 501, "limitLeg": 2,
    "statsData": [{"tpid": "aaaa"}, {"tpid": "bbbb"}],
    "legData": [
      {"first": 0, "winner": 1, "currentRound": 5, "currentPlayer": 1, "endFlag": 1,
       "playerData": [
         [{"score": 0, "left": 501}, {"score": 100, "left": 401}, {"score": 60, "left": 341}, {"score": 85, "left": 256}, {"score": 100, "left": 156}, {"score": 60, "left": 96}],
         [{"score": 0, "left": 501}, {"score": 140, "left": 361}, {"score": 100, "left": 261}, {"score": 81, "left": 180}, {"score": 140, "left": 40}, {"score": 60, "left": -20}, {"score": -2, "left": 0}]
       ]}
    ]
  }
}
{"result":0, "mid":"Ab3kR9xz_1700000000000", "tmid":"t_xxxx_rr_0_aaaa_bbbb", "startTime":1105335600, "updateTime":1700000000000}
The bracket result (*_result) is not written; use /api/v1/tournament/result/update to enter the result together with the match data. Creating a match updates the updateTime of the tournament and sends the update notification (the statistics cache is rebuilt). mid, the delete flag, internal fields and tdid / lgid cannot be given in set (result: -3).

POST/api/v1/match/update

Updates a match. The archive copy is the primary target; when the match also exists among the matches in progress, both are updated at the same time to keep them in sync. All public fields returned by /api/v1/match/get can be specified, including statsData (mid, the delete flag, internal fields and the identification of the tournament and bracket the match belongs to (tdid lgid tmid schid scid ttype round gs_round) cannot be updated). When statsData is updated, the items that the retrieval API masks keep their server-side values. Only the administrator of the tournament the match belongs to (tdid) can update it (a match without a tdid cannot be updated).

{
  "mid": "match ID",
  "set": {"title": "Grand Final", "private": 1}
}

The values of the following fields are validated.

FieldValue
titleString (up to 200 characters)
private0 / 1 (hide from the history list)
Updating a match also updates the updateTime of the tournament it belongs to and sends the update notification (the statistics cache is rebuilt).

POST/api/v1/match/delete

Deletes a match (a soft delete that sets the delete flag). When the match exists both in the archive and among the matches in progress, both are flagged. As with the update, only the administrator of the tournament the match belongs to (tdid) can do this (a match without a tdid cannot be deleted).

{"mid": "match ID"}
Deleting a match updates the tournament's updateTime and sends an update notification, but the bracket results (*_result) and the team order results are not recalculated. Update the bracket with /api/v1/tournament/update when you need to.

POST/api/v1/team/player/update

Adds, updates, and removes the members of a team (tpid). add / update / remove are all optional; specify only what you need.

{
  "tdid": "tournament ID",
  "add": [{"tpid": "aaaa", "oname": "Team Member", "opid": "P-01", "index": 1}],
  "update": [{"tpid": "aaaa", "oid": "Xy3f", "oname": "Renamed Member"}],
  "remove": [{"tpid": "aaaa", "oid": "Ab1c"}]
}

The values of the following fields are validated.

FieldValue
onamePlayer name (control characters are removed; up to 60 characters, longer values are rejected with result: -3). Required when adding
opidPlayer number or similar (up to 20 characters)
indexInteger. Sort order
delete0 / 1 (deleted state)

add requires tpid and oname, update / remove require tpid and oid (otherwise result: -3; result: -51 when all three are empty). Added members get a newly assigned oid, returned in the response's added (lgid is inherited from the tournament). update and remove address a member by tpid and oid.

{"result":0, "added":[{"tpid":"aaaa", "oid":"Xy3f", "oname":"Team Member"}], "updated":1, "removed":1}
remove is a soft delete that sets the delete flag (names already used in an order are still displayed). Send "delete": 0 with update to restore a member. Deleted members can be listed with /api/v1/team/player/list?...&all=1 (administrators of that tournament only).

POST/api/v1/team/order/update

Registers, updates and removes team orders. update stores the order for a (tmid, tpid, schid) combination and adds it when it does not exist yet (the number of added orders is returned in added).

{
  "tdid": "tournament ID",
  "update": [
    {"tmid": "...", "tpid": "aaaa", "schid": "...", "order": [{"oid": "Xy3f"}, {"oid": "Ab1c"}]}
  ],
  "remove": [{"tmid": "...", "tpid": "aaaa", "schid": "..."}]
}
{"result":0, "added":1, "updated":0, "removed":1}
FieldValue
orderArray of the order (up to 200 items). Each item has oid and optionally modify (0 / 1)
The order is also reflected into the statsData order of the matching game with the player names filled in, and an update notification for the order pages is sent. remove deletes the order and empties the order on the match side. The order result (res) cannot be updated, because it implies recalculating the bracket; update results with /api/v1/tournament/update.

POST/api/v1/tournament/result/update

Enters (or clears) the result of one match with the same processing as the result input of the management screen. The server writes both sides of <ttype>_result, advances the winner to the next round (and the loser of a double elimination to the losers bracket), fills the third place match and finishes the tournament (status 40) when auto_complete is on and every match is over. Writing *_result directly with /api/v1/tournament/update does none of this, so use this API to enter results.

{
  "tdid": "tournament ID",
  "ttype": "t",
  "round": 0,
  "t_no": 1,
  "tpid": "aaaa",
  "vsTpid": "bbbb",
  "result": 3,
  "vsResult": 1,
  "detail": {"a": 65.2, "t": 4, "t4": 1, "t8": 0, "h": 80, "b": 15},
  "vsDetail": {"a": 58.0}
}
FieldValue
ttypet t3 s2 s2_3 rr lg dw dl m
roundRound index (first round = 0). Block index for rr, match index for m, the string "<division>_<lsid>" for lg
t_noMatch number in the round (1-based) for t t3 s2 s2_3 dw dl; 0 otherwise
tpid vsTpidThe two players (teams). For a bye of a normal league pass "empty" as vsTpid
result vsResultLegs won by each side (sets in a set format, games won in a team event). Pass both as null to clear the result
detail vsDetailOptional statistics (a average, t 100+, t4 140+, t7 170+, t8 180, h high out, b best leg, a_b / w_b legs played and won as second thrower, mk cricket mark distribution, add bonus points, g legs per game of a team event, l legs of a set format). An unknown key or a value that is not a number / array of numbers is refused with result: -51

tpid and vsTpid must differ, and result / vsResult must both be numbers or both null. Invalid parameters (ttype, round, t_no, ...) are refused with result: -51; when the management backend does not accept the request, result: -3 is returned.

The processing is delegated to the PHP of the management screen with the management token of the competition, so this API and the management screen always behave the same. When the management backend cannot be reached, result: -62 is returned.

POST/api/v1/league/schedule/update

Replaces the fixtures (match cards) of one division of the league format as a whole, with the same processing as saving the cards on the management screen. The results of swiss byes (p is [tpid, "empty"]) are recorded by the server.

{
  "tdid": "tournament ID",
  "div": 0,
  "schedule": [
    {"p": ["aaaa", "bbbb"], "lsid": "ab3f", "t": ""},
    {"p": ["cccc", "dddd"]}
  ],
  "expect": 2
}
FieldValue
divRequired. Division index (0-1024)
scheduleEvery card of the division (at most 4096). Each item has p (required; two tpid, "" empty slot / "empty" bye), lsid (4 lower-case letters / digits; keep the value of existing cards and never repeat one: a card with a new lsid is a different card and loses its result; omit it for new cards), t (title, cut at 100 characters), r (swiss round number, 1-1024)
expectOptional. The current number of cards the change is based on. When it differs from the server, the update is refused with result: -7 and nothing is written (protection against concurrent changes from another device)

The response carries the stored schedule including the assigned lsid, and div. Both update and generate require the league format (lg_setting.league = 1) and refuse anything else with result: -51.

POST/api/v1/league/schedule/generate

Generates the fixtures from lg_table (the players of each division) and saves them, with the same rules as the automatic pairing and the swiss buttons of the management screen. Without div every division is processed. swiss_* on a normal league, robin on a swiss league, and a missing robin_count are refused with result: -51.

{"tdid": "tournament ID", "div": 0, "mode": "auto"}
modeAction
robinRound robin (normal league): every pairing (twice with turnaround); cards that already have a result keep their lsid
swiss_firstCreates the empty slots of round 1 of a swiss league (⌈players / 2⌉ rows)
swiss_assignFills the empty slots with the unassigned players at random (one bye when the count is odd)
swiss_nextGenerates the next round (paired by rank within the point groups, avoiding rematches and repeated floats; rematch counts the unavoidable rematches)
auto (default)robin for a normal league. For a swiss league: round 1 with random assignment when there is no round yet, the assignment when slots are empty, else the next round
{"result":0, "swiss":1, "divisions":[
  {"div":0, "before":3, "action":"swiss_next", "round":2, "total":3, "blank":0, "rematch":0, "after":6, "schedule":[...]}
]}

Divisions that were not processed carry the reason in skipped (not enough players, every round created, empty slots left, ...). Each division is saved with its current card count as expect, so a concurrent change on another device gives result: -7.

POST/api/v1/league/tournament/link

Makes a tournament an event of a league (same as linking a season on the management screen). lgid and tdid are required and you must administer both. lgid and the private flag of the league are set on the tournament and its matches.

{"lgid": "league ID", "tdid": "tournament ID"}

POST/api/v1/league/tournament/unlink

Detaches an event from its league (same as unlinking on the management screen). lgid is removed from the tournament, its entries, its team members and its matches. lgid and tdid are required and you must administer both; when the tournament does not belong to that league the request is refused with result: -51.

{"lgid": "league ID", "tdid": "tournament ID"}

POST/api/v1/team/order/fix

Fixes (fix 1) or releases (fix 0) the order of a team, as the administrator does on the order page. Once both teams have fixed, each can see the order of the other.

{"tdid": "tournament ID", "tmid": "match card ID", "tpid": "aaaa", "vsTpid": "bbbb", "fix": 1}

POST/api/v1/team/order/result

Enters the result of one game (schid) of a team match card by hand (same as the result input of the card on the management screen). The server counts the games won, writes the card result into <ttype>_result and advances the bracket.

{
  "tdid": "tournament ID",
  "tmid": "match card ID",
  "schid": "a1b2",
  "ttype": "t",
  "round": 0,
  "t_no": 1,
  "tpid": "aaaa",
  "vsTpid": "bbbb",
  "p1res": {"r": 3, "a": 70.5},
  "p2res": {"r": 1, "a": 61.0}
}
FieldValue
ttype round t_noSame as tournament/result/update
gs_roundOptional. The round used for the round-specific game settings (default: round, the division for lg)
p1res p2resResults of tpid / vsTpid. r (legs won) is required; the other keys are the statistics of detail

POST/api/v1/tournament/badge/update

Sets the badge (board number) of matches, like the badge management of the management screen. Pass one badge in the body or several in list. Participants see the change immediately through the update notification.

{"tdid": "tournament ID", "ttype": "t", "round": 0, "index": 2, "str": "5", "st": 1}
{"tdid": "tournament ID", "list": [{"ttype": "t", "round": 0, "index": 2, "str": ""}, {"ttype": "rr", "round": 1, "index": 0, "str": "A-3", "st": 2}]}
FieldValue
ttypet t3 s2 s2_3 dw dl m rr lg
round indexRound index and slot index (the match of slots 2k and 2k+1 is t_no k+1). The badge key is "<ttype>-<round>-<index>"
strBoard text (up to 40 characters). "" removes the badge
st0 none / 1 in progress (default when str is set) / 2 finished
t_memo t_memo_tpidOptional. Also writes the memo of the match (e.g. the referee). A match that already has a memo is left alone, and nothing is written when t_memo_tpid plays in that match (the same rule as the automatic referee)
listSeveral badges in one request (1-200)
{"result":0, "updated":2}

POST/api/v1/tournament/memo/update

Sets the memo shown under each round robin block (ttype rr) or league division (lg). memo is an array of strings, one per block / division (at most 1024 items, each cut at 200 characters); an empty array clears them.

{"tdid": "tournament ID", "ttype": "rr", "memo": ["Board 36", "Board 37"]}

POST/api/v1/tournament/t_memo/update

Sets the memo shown at a match of a bracket (up to 40 characters, e.g. the referee). key is "<ttype>-<round>-<index>" with the even slot index of the match (the same key as a badge); str "" clears it. Pass one in the body or several (1-200) in list. The response carries updated (the count).

{"tdid": "tournament ID", "key": "t-0-2", "str": "Referee: Taro"}

POST/api/v1/tournament/announce/update

Sets the announcement shown to the participants (up to 200 characters). "" clears it. announceTime (UNIX milliseconds) defaults to the current time, or to 0 when the announcement is cleared. The response returns the stored announce / announceTime.

{"tdid": "tournament ID", "announce": "The final starts at 18:00"}

POST/api/v1/tournament/assign/update

Saves how the qualifiers of the round robin / league groups are assigned to the final brackets (assign_setting). The values are sanitized with the same rules as the assignment settings of the management screen and the stored assign_setting is returned. assign replaces the stored settings as a whole (it is not a partial update): omitted items get their defaults (t_type=top / s2_type=low / count=2 / every flag false / referee_type=lowest) and out-of-range values are replaced by the default instead of being rejected. The current values are in assign_setting of tournament/get.

{"tdid": "tournament ID", "assign": {"t_type": "top", "t_count": 2, "t_complete": true, "s2_type": "low", "s2_count": 2}}
Field (prefixed with t_ / s2_)Value
typetop / low / custom (per group size)
countPlayers taken from each group (1-99)
placeholder complete refereetrue / false. Show rank placeholders in undecided slots / assign finished groups only / set referees
referee_typelowest / random
custom{"<group size>": {"type": "top", "count": 2}}

POST/api/v1/tournament/copy

Copies a tournament (same as the copy of the management screen: status 10, same settings, same league) and returns the new tdid and url.

{"tdid": "tournament ID", "title": "Autumn Open 2027", "date": 0, "entry": 1, "result": 0}
FieldValue
titleOptional. Title of the copy, up to 60 characters (default: the same title)
date1 keeps the date (default 0)
entry1 copies the entries and the tables (default 0; the badges, match order and match memos are copied with them)
result1 also copies the results (needs entry 1; default 0)
guide1 also copies the guide (the initial bracket {ttype}_init; default 0)
{"result":0, "tdid":"t_Ab1c_2345", "url":"https://n01darts.com/n01/tournament/comp.php?id=t_Ab1c_2345"}

POST/api/v1/tournament/match/release

Releases the game lock (same as "Release game lock" in the match menu of the management screen). When n01 Live refuses to start a match card (tmid, optionally one game schid of a team event) because the players are "locked, playing elsewhere", this clears the in-game state of both players so that they can start again. The match data, the bracket and the results are not touched.

{"tdid": "tournament ID", "tmid": "match card ID"}

POST/api/v1/autopilot/update

Updates the autopilot settings. Only the fields given in config replace the stored ones (types is merged per type), the values are sanitized with the same rules as the settings page and the autopilot server is notified immediately. The stored settings are returned.

{"tdid": "tournament ID", "config": {"types": {"t": {"badge_number": "1-10,12", "break_time": 5, "round": 2.5, "enable": 1}}, "remove_old_badge": 1}}
FieldValue
types.<t|s2|dw|dl>.badge_numberBoards to use (e.g. "1-10,12", up to 200 characters)
types.<t>.break_timeBreak after a match (minutes, 0-1440)
types.<t>.roundRounds to assign (0-99 in steps of 0.5). 0 every round / x up to round x / .5 adds the third place match (only when x is the round before the final; the final is never included)
types.<t>.enable0 / 1. Run the automatic assignment
remove_old_badge set_referee0 / 1. Remove the badges of finished matches / set referees
referee_typesame_board / prev_upper / prev_lower / prev_random
name_control name_mode name_sep name_stop name_regex priority hold_robinName extraction and priority (when the same people play several events). name_mode is auto / simple / regex, priority -99 to 99

7. Result codes

resultHTTPMeaning
0200Success
-1404Target not found (does not exist / deleted)
-3400Invalid update field (not allowed / invalid value)
-5402The players of the tournament exceed the limit the organizer has paid for; it cannot be set to status 30 (in progress)
-6502The player limit could not be verified (payment server error); the tournament is not started
-7409The target has been updated since expect_update_time (expect for fixtures); nothing is written
-40401Authentication error
-41403Permission error (not the administrator of the data / no admin_id)
-42402No API subscription / the subscription has expired
-43403Access from the client's IP address is denied
-50400 / 413 / 415Invalid request body (not valid JSON; 413 when the body exceeds 1MB; 415 when Content-Type is not application/json)
-51400Invalid parameter
-52404Unknown endpoint
-53405Method not allowed
-54503The query took too long (list APIs are cut off after 10 seconds); narrow the filter and retry
-55429Too many requests in a short time (a per-address limit, about 300 requests per minute). Wait the seconds given in the Retry-After header and retry. MCP requests are refused with the same HTTP 429
-60501The statistics API or the management (PHP) backend used by the result / fixture / badge / autopilot APIs is disabled (not configured on the server)
-61502Statistics server error
-62502The management backend (PHP) could not be reached or refused the operation (APIs that go through the management screen: results, fixtures, badges, ...)
-99500Internal server error

8. Examples (curl)

# Tournaments in progress
curl "https://push.n01darts.com/api/v1/tournament/list?status=30&count=20"

# A single tournament (with entries)
curl "https://push.n01darts.com/api/v1/tournament/get?tdid=XXXX"

# Tournament statistics
curl "https://push.n01darts.com/api/v1/tournament/stats?tdid=XXXX&kind=stats_list"

# Finished matches of a tournament, ordered by start time
curl "https://push.n01darts.com/api/v1/match/list?tdid=XXXX&endMatch=1&sort=startTime&order=asc"

# Team orders
curl "https://push.n01darts.com/api/v1/team/order/list?tdid=XXXX&tmid=YYYY"

# Update a tournament title
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"tdid":"XXXX","set":{"title":"Spring Open 2026"}}' \
     "https://push.n01darts.com/api/v1/tournament/update"

# Add an entry
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"tdid":"XXXX","add":[{"name":"New Player","c":"JP"}]}' \
     "https://push.n01darts.com/api/v1/tournament/entry/update"

# Tournaments you administer (including the private ones)
curl -u apiuser:apipass "https://push.n01darts.com/api/v1/tournament/list?owner=1"

# Create a tournament (with entries)
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"set":{"title":"Autumn Open","status":20,"join_pass":"pass1234"},
          "entry_list":[{"name":"Player One","c":"JP"}]}' \
     "https://push.n01darts.com/api/v1/tournament/create"

# Create a league
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"set":{"title":"Winter League"}}' \
     "https://push.n01darts.com/api/v1/league/create"

# Delete a tournament
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"tdid":"XXXX"}' \
     "https://push.n01darts.com/api/v1/tournament/delete"

# Enter the result of the first match of round 1 (the winner advances)
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"tdid":"XXXX","ttype":"t","round":0,"t_no":1,"tpid":"aaaa","vsTpid":"bbbb","result":3,"vsResult":1}' \
     "https://push.n01darts.com/api/v1/tournament/result/update"

# Generate the league fixtures (the next round of a swiss league)
curl -u apiuser:apipass -H "Content-Type: application/json" \
     -d '{"tdid":"XXXX"}' \
     "https://push.n01darts.com/api/v1/league/schedule/generate"

# Standings
curl "https://push.n01darts.com/api/v1/tournament/standings?tdid=XXXX"

9. Live samples

This manual is served by the API server itself, so the links below call the actual API on the same server. Clicking a URL opens the resulting JSON in a new tab. Clicking "Run" shows the formatted result at the bottom of this page.

SampleDescription
health Health check
tournament/list?count=5 Latest 5 tournaments
tournament/list?status__in=20,30&sort=updateTime&count=5 5 open/in-progress tournaments by update time
league/list?count=5 Latest 5 leagues
match/list?count=5 Latest 5 matches
match/list?match_type=cricket&count=5 5 Cricket matches

Using the tdid / lgid / mid values found in the list results, you can try tournament/get?tdid=... and match/get?mid=... in the browser address bar the same way.

10. MCP server

The API server also works as an MCP (Model Context Protocol) server, so AI agents such as Claude Code can call this API directly as tools. The transport is Streamable HTTP with a single endpoint.

POST /api/v1/mcp

Tools

Data retrieval (authentication optional)

ToolREST API
n01_health/api/v1/health
n01_tournament_list/api/v1/tournament/list
n01_tournament_get/api/v1/tournament/get
n01_tournament_entry_list/api/v1/tournament/entry/list
n01_tournament_stats/api/v1/tournament/stats
n01_league_list/api/v1/league/list
n01_league_get/api/v1/league/get
n01_league_entry_list/api/v1/league/entry/list
n01_league_tournament_list/api/v1/league/tournament/list
n01_match_list/api/v1/match/list
n01_match_get/api/v1/match/get
n01_team_order_list/api/v1/team/order/list
n01_team_player_list/api/v1/team/player/list
n01_tournament_standings/api/v1/tournament/standings
n01_tournament_end_group/api/v1/tournament/end_group
n01_league_schedule_get/api/v1/league/schedule/get
n01_league_stats/api/v1/league/stats
n01_autopilot_get/api/v1/autopilot/get (administrator authentication required)
n01_autopilot_list/api/v1/autopilot/list (administrator authentication required)

Create / update / delete (Basic authentication or OAuth; not listed on unauthenticated connections)

ToolREST API
n01_tournament_create/api/v1/tournament/create
n01_tournament_update/api/v1/tournament/update
n01_tournament_delete/api/v1/tournament/delete
n01_tournament_entry_update/api/v1/tournament/entry/update
n01_league_create/api/v1/league/create
n01_league_update/api/v1/league/update
n01_league_delete/api/v1/league/delete
n01_league_entry_update/api/v1/league/entry/update
n01_match_create/api/v1/match/create
n01_match_update/api/v1/match/update
n01_match_delete/api/v1/match/delete
n01_team_player_update/api/v1/team/player/update
n01_team_order_update/api/v1/team/order/update
n01_team_order_fix/api/v1/team/order/fix
n01_team_order_result/api/v1/team/order/result
n01_tournament_result_update/api/v1/tournament/result/update
n01_league_schedule_update/api/v1/league/schedule/update
n01_league_schedule_generate/api/v1/league/schedule/generate
n01_league_tournament_link/api/v1/league/tournament/link
n01_league_tournament_unlink/api/v1/league/tournament/unlink
n01_tournament_badge_update/api/v1/tournament/badge/update
n01_tournament_memo_update/api/v1/tournament/memo/update
n01_tournament_t_memo_update/api/v1/tournament/t_memo/update
n01_tournament_announce_update/api/v1/tournament/announce/update
n01_tournament_assign_update/api/v1/tournament/assign/update
n01_tournament_copy/api/v1/tournament/copy
n01_tournament_match_release/api/v1/tournament/match/release
n01_autopilot_update/api/v1/autopilot/update

Connecting from Claude Code

# read only (no authentication)
claude mcp add --transport http n01 https://push.n01darts.com/api/v1/mcp

# with updates (Basic authentication)
claude mcp add --transport http n01 https://push.n01darts.com/api/v1/mcp \
    --header "Authorization: Basic $(printf '%s' 'apiuser:apipass' | base64)"

To share the configuration in a project, put it in .mcp.json (pass the credentials through an environment variable).

{
  "mcpServers": {
    "n01": {
      "type": "http",
      "url": "https://push.n01darts.com/api/v1/mcp",
      "headers": {"Authorization": "Basic ${N01_API_BASIC}"}
    }
  }
}

Connecting from claude.ai

In claude.ai open Settings → Connectors → "Add custom connector" and register the URL https://push.n01darts.com/api/v1/mcp. Choose OAuth as the authentication: the n01 login page opens, and after you log in with the account you administer your competitions with and allow the access, the create / update / delete tools are available as that administrator (OAuth 2.1). Registered without authentication, only the data retrieval tools are available.