├── .editorconfig ├── .github └── workflows │ └── tests.yml ├── .vscode └── tasks.json ├── Dockerfile ├── License.md ├── Readme.md ├── build.sh ├── components ├── Controller.php ├── PageInfo.php └── Parsedown.php ├── controllers └── IndexController.php ├── docs ├── auth │ ├── dedi.md │ ├── index.md │ ├── token.md │ └── ubi.md ├── core │ ├── accounts │ │ ├── club-tags.md │ │ ├── display-names.md │ │ ├── webidentities.md │ │ └── zones.md │ ├── index.md │ ├── maps │ │ ├── authored.md │ │ ├── info-multiple.md │ │ ├── info.md │ │ ├── set-vote.md │ │ ├── submitted.md │ │ └── vote.md │ ├── meta │ │ ├── routes.md │ │ └── zones.md │ ├── records │ │ ├── account-records-v2.md │ │ ├── map-record.md │ │ ├── map-records-v2.md │ │ └── map-records.md │ └── skins │ │ ├── equipped.md │ │ ├── favorites.md │ │ └── info.md ├── glossary.md ├── index.md ├── live │ ├── campaigns │ │ ├── campaigns-v2.md │ │ ├── campaigns.md │ │ ├── map-info.md │ │ ├── totds.md │ │ └── weekly-shorts.md │ ├── clubs │ │ ├── activities.md │ │ ├── campaign-by-id.md │ │ ├── campaigns.md │ │ ├── club.md │ │ ├── clubs-mine.md │ │ ├── clubs.md │ │ ├── competitions.md │ │ ├── map-review.md │ │ ├── member-by-name.md │ │ ├── member.md │ │ ├── members.md │ │ ├── player.md │ │ ├── room-by-id.md │ │ ├── rooms.md │ │ ├── upload-by-id.md │ │ └── uploads.md │ ├── index.md │ ├── leaderboards │ │ ├── campaign-ranking.md │ │ ├── campaign-top.md │ │ ├── medals.md │ │ ├── position.md │ │ ├── surround.md │ │ ├── top-club.md │ │ ├── top.md │ │ └── trophies.md │ ├── maniapubs │ │ └── active.md │ └── maps │ │ ├── add-favorite.md │ │ ├── favorites.md │ │ ├── info-multiple.md │ │ ├── info.md │ │ ├── remove-favorite.md │ │ └── uploaded.md ├── meet │ ├── challenges │ │ ├── challenge.md │ │ ├── challenges.md │ │ ├── leaderboard.md │ │ └── map-records.md │ ├── club-competitions │ │ ├── club-competition.md │ │ └── club-competitions.md │ ├── competition-matches │ │ ├── matches-for-round.md │ │ ├── player-matches.md │ │ └── results.md │ ├── competitions │ │ ├── competition.md │ │ ├── competitions.md │ │ ├── leaderboard.md │ │ ├── participants.md │ │ ├── rounds.md │ │ └── teams.md │ ├── cup-of-the-day │ │ └── current.md │ ├── index.md │ ├── matches │ │ ├── match.md │ │ ├── participants.md │ │ └── teams.md │ ├── matchmaking │ │ ├── divisions.md │ │ ├── player-ranking.md │ │ ├── rankings.md │ │ └── summary.md │ └── super-royal │ │ ├── statistics.md │ │ └── status.md └── oauth │ ├── auth.md │ ├── index.md │ ├── reference │ ├── accounts │ │ ├── id-to-name.md │ │ ├── name-to-id.md │ │ └── player.md │ ├── clubs │ │ └── admin-clubs.md │ └── favorites │ │ ├── add-favorite.md │ │ ├── favorites.md │ │ └── remove-favorite.md │ └── summary.md ├── public ├── css │ ├── Atkinson-Hyperlegible-Bold-102a.woff2 │ ├── Atkinson-Hyperlegible-BoldItalic-102a.woff2 │ ├── Atkinson-Hyperlegible-Italic-102a.woff2 │ └── Atkinson-Hyperlegible-Regular-102a.woff2 ├── img │ ├── android-chrome-192x192.png │ ├── android-chrome-256x256.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── logo_icon.png │ └── safari-pinned-tab.svg ├── index.php ├── js │ └── script.js ├── manifest.json └── style.css ├── push.sh ├── test.py └── views ├── error.php ├── index ├── api-param.php ├── api.php ├── page-index.php ├── page-list.php └── page.php ├── layout.php └── menu ├── item.php └── menu.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.md] 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.php] 12 | indent_style = tab 13 | 14 | [*.js] 15 | indent_style = tab 16 | 17 | [public/components/Parsedown.php] 18 | indent_style = space 19 | indent_size = 4 20 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | tests: 13 | name: Unit Tests 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Check out repository 17 | uses: actions/checkout@v1 18 | - name: Setup Python v3.11 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: '3.11' 22 | - name: Install pyyaml 23 | run: pip install pyyaml 24 | - name: Run tests 25 | run: python test.py 26 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build Docker Image", 8 | "type": "shell", 9 | "command": "docker", 10 | "args": [ 11 | "build", 12 | "-t", 13 | "op-nadeoapi-docs", 14 | "." 15 | ], 16 | "problemMatcher": [], 17 | "group": { 18 | "kind": "build", 19 | "isDefault": true 20 | } 21 | }, 22 | { 23 | "label": "Run Docker Image", 24 | "type": "shell", 25 | "command": "docker", 26 | "args": [ 27 | "run", 28 | "--rm", 29 | "-v", 30 | "${workspaceRoot}:/var/www/html", 31 | "-p", 32 | "80:80", 33 | "op-nadeoapi-docs" 34 | ], 35 | "isBackground": true, 36 | "problemMatcher": [] 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codecatt/nin:latest 2 | RUN apk add php82-pecl-yaml 3 | COPY . /var/www/html 4 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Copyright © 2022 Openplanet.dev 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Trackmania API documentation 2 | [![Tests](https://github.com/openplanet-nl/nadeoapi-docs/actions/workflows/tests.yml/badge.svg)](https://github.com/openplanet-nl/nadeoapi-docs/actions/workflows/tests.yml) 3 | 4 | [Visit the documentation here](https://webservices.openplanet.dev/). 5 | 6 | ## Running the documentation locally 7 | Docker is the recommended way of developing the site, and also for testing documentation changes locally. 8 | 9 | 1. Build the docker image: 10 | ``` 11 | docker build -t op-nadeoapi-docs . 12 | ``` 13 | 2. Start a container: 14 | ``` 15 | docker run --rm -v $(pwd):/var/www/html -p 80:80 op-nadeoapi-docs 16 | ``` 17 | 3. Visit http://127.0.0.1/ 18 | 19 | ## Running tests 20 | Content tests run automatically on a push to the repository. To run them locally, you need Python and PyYAML. Then, simply run the test script: 21 | 22 | ``` 23 | $ ./test.py 24 | ``` 25 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker build -t registry.mrag.nl/openplanet/nadeo-api . 3 | -------------------------------------------------------------------------------- /components/PageInfo.php: -------------------------------------------------------------------------------- 1 | meta = yaml_parse($frontmatter); 17 | $this->markdown = trim(substr($markdown_contents, $next_pos + 4)); 18 | } else { 19 | $this->markdown = trim($markdown_contents); 20 | } 21 | } 22 | 23 | public function isAPIEndpoint() 24 | { 25 | return $this->meta !== null && isset($this->meta['route']); 26 | } 27 | 28 | public function isAPIIndex() 29 | { 30 | return $this->meta !== null && isset($this->meta['index']); 31 | } 32 | 33 | public function getPosition() 34 | { 35 | if ($this->meta !== null && isset($this->meta['position'])) { 36 | return intval($this->meta['position']); 37 | } 38 | return 0; 39 | } 40 | 41 | public function getName() 42 | { 43 | if ($this->meta !== null && isset($this->meta['name'])) { 44 | return $this->meta['name']; 45 | } 46 | 47 | $matchTitle = false; 48 | if (preg_match('/^# (.*)/', $this->markdown, $matchTitle)) { 49 | return $matchTitle[1]; 50 | } 51 | 52 | return ''; 53 | } 54 | 55 | public function getView() 56 | { 57 | if ($this->isAPIEndpoint()) { 58 | return 'api'; 59 | } 60 | return 'page'; 61 | } 62 | 63 | public function getHtml() 64 | { 65 | $parsedown = new Parsedown(); 66 | return $parsedown->text($this->markdown); 67 | } 68 | 69 | public function getRouteHtml() 70 | { 71 | if (!$this->isAPIEndpoint()) { 72 | return false; 73 | } 74 | 75 | $ret = '' . Nin\Html::encode($this->meta['url']) . ''; 76 | 77 | $ret .= preg_replace_callback('/\\{([a-zA-Z0-9]+)\\}/', function($m) { 78 | return '' . $m[0] . ''; 79 | }, Nin\Html::encode($this->meta['route'])); 80 | 81 | if (isset($meta['parameters']) && isset($meta['parameters']['query'])) { 82 | $n = 0; 83 | foreach ($meta['parameters']['query'] as $item) { 84 | if (!isset($item['required']) || !$item['required']) { 85 | continue; 86 | } 87 | if ($n == 0) { 88 | $ret .= '?'; 89 | } else { 90 | $ret .= '&'; 91 | } 92 | $n++; 93 | $ret .= Nin\Html::encode($item['name']) . '='; 94 | $ret .= ''; 95 | $ret .= '{' . Nin\Html::encode($item['name']) . '}'; 96 | $ret .= ''; 97 | } 98 | } 99 | 100 | return $ret; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /controllers/IndexController.php: -------------------------------------------------------------------------------- 1 | displayError('Invalid path', 400); 9 | return; 10 | } 11 | 12 | if (str_ends_with($path, '/')) { 13 | $path = substr($path, 0, -1); 14 | } 15 | 16 | if ($path == 'index' || str_ends_with($path, '/index')) { 17 | $base = dirname($path); 18 | if ($base == '.') { 19 | $base = ''; 20 | } 21 | $this->redirect('/' . $base, 301); 22 | return; 23 | } 24 | 25 | $indexInfo = false; 26 | if ($path != '') { 27 | $indexInfo = $this->getPageIndexInfo($path); 28 | if ($indexInfo === false) { 29 | $this->render404($path); 30 | return; 31 | } 32 | } 33 | 34 | $this->renderPage($path, $indexInfo); 35 | } 36 | 37 | private function render404(string $path) 38 | { 39 | $this->displayError('Page not found: ' . $path, 404); 40 | } 41 | 42 | private function renderIndex(string $path, $info) 43 | { 44 | $this->title = $info['name']; 45 | 46 | $this->render('page-index', [ 47 | 'path' => $path, 48 | 'info' => $info, 49 | ]); 50 | } 51 | 52 | private function renderPage(string $path, $info) 53 | { 54 | global $nf_project_dir; 55 | 56 | $docs_dir = realpath($nf_project_dir . '/docs'); 57 | 58 | $page_path = $docs_dir . '/' . $path . '.md'; 59 | if (!file_exists($page_path)) { 60 | $page_path = $docs_dir . '/'; 61 | if ($path == '') { 62 | $page_path .= 'index.md'; 63 | } else { 64 | $page_path .= $path . '/index.md'; 65 | } 66 | if (!file_exists($page_path)) { 67 | $this->renderIndex($path, $info); 68 | return; 69 | } 70 | } 71 | 72 | $page = new PageInfo($page_path); 73 | 74 | $this->title = $page->getName(); 75 | 76 | $this->render($page->getView(), [ 77 | 'path' => $path, 78 | 'page' => $page, 79 | 'info' => $info, 80 | ]); 81 | } 82 | 83 | public function actionApiIndex() 84 | { 85 | header('Content-Type: application/json'); 86 | echo json_encode($this->getPageIndex()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /docs/auth/dedi.md: -------------------------------------------------------------------------------- 1 | --- 2 | position: 1 3 | --- 4 | # Dedicated server account 5 | 6 | If you don't want to or can't use a Ubisoft account for authentication, you can use a [dedicated server account](https://www.trackmania.com/player/dedicated-servers). Note that there are some limitations on what you can do with dedicated server tokens (as noted on relevant API endpoint documentation pages). 7 | 8 | ## Setting up a dedicated server account 9 | 10 | A dedicated server account is always bound to a Ubisoft account. Visit [Trackmania.com's dedicated servers page](https://www.trackmania.com/player/dedicated-servers) to create a dedicated server account. 11 | 12 | Make sure to store the password after creating your account as it can't be retrieved again later. 13 | 14 | Note that your dedicated server account is directly associated to a Ubisoft account - if Nadeo/Ubisoft detect API usage they deem unacceptable, restrictions or bans on your dedicated server account may also have consequences for your associated Ubisoft account. 15 | 16 | ## Acquiring a Nadeo API access token 17 | 18 | Send the following HTTP request using a tool/library of your choice: 19 | 20 | ```plain 21 | POST https://prod.trackmania.core.nadeo.online/v2/authentication/token/basic 22 | 23 | Headers: 24 | Content-Type: application/json 25 | Authorization: Basic 26 | User-Agent: 27 | 28 | Body: 29 | { "audience": "NadeoLiveServices" } 30 | ``` 31 | 32 | The `Authorization` header uses [Basic HTTP authentication](https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side) for your dedicated server account credentials (e.g. `username:password` becomes `Basic dXNlcm5hbWU6cGFzc3dvcmQ=`). 33 | In Go for example, this is done via [SetBasicAuth](https://pkg.go.dev/net/http#Request.SetBasicAuth) - other languages and libraries have their own utility methods for the same purpose. 34 | 35 | The body of the request must be a JSON object with the desired audience name. The audience(s) you need depend on the APIs and endpoints you intend to interact with. 36 | 37 | | URL | Audience | 38 | | -------------------------------------------- | ----------------- | 39 | | | NadeoServices | 40 | | | NadeoLiveServices | 41 | | | NadeoLiveServices | 42 | 43 | Note that if you don't provide a body, you get a token for the audience `NadeoServices`. 44 | 45 | If you plan to interact with API endpoints that require different audiences, you need to request multiple tokens and manage them separately. 46 | 47 | ## Next steps 48 | 49 | The response body contains an `accessToken` and a `refreshToken` which you can use for your API requests. See the [token usage guide](/auth/token) for information on how to use and manage tokens. 50 | -------------------------------------------------------------------------------- /docs/auth/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Authentication 3 | category: general 4 | icon: fa-lock 5 | pages: 6 | - ubi 7 | - dedi 8 | - token 9 | --- 10 | 11 | # Authentication 12 | 13 | This guide explains how to authenticate with Nadeo's APIs. There are 2 available methods: 14 | 15 | - [via a dedicated server account](/auth/dedi) 16 | - [via a Ubisoft account](/auth/ubi) 17 | 18 | Dedicated server account authentication is easier to implement but imposes some limitations on what you can access with the API. The relevant restrictions are documented on each of the endpoint documentation pages. 19 | 20 | Both authentication paths result in one or more access tokens - see the [token usage guide](/auth/token) for information on how to use and manage them. 21 | 22 | For a complete authentication implementation example, you can refer to [Miss' Nadeo Go package](https://github.com/codecat/gonadeo). 23 | 24 | ## Authentication in Openplanet 25 | 26 | If you need to make requests to Nadeo API endpoints from inside an Openplanet plugin, don't handle any of the authentication logic yourself. Instead, use the [NadeoServices dependency](https://openplanet.dev/docs/reference/nadeoservices) as a central authentication plugin. 27 | -------------------------------------------------------------------------------- /docs/core/accounts/club-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player club tags 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /accounts/clubTags/?accountIdList={accountIdList} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: accountIdList 13 | type: string 14 | description: A comma-separated list of account IDs 15 | required: true 16 | --- 17 | 18 | Gets player club tags from account IDs. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - This endpoint is only accessible with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). If you encounter `401` errors using a dedicated server account, switch to using a Ubisoft account. 25 | - This endpoint has no intrinsic limit on the number of account IDs requested, but it will return a `414` error if the request URI length is 8220 characters or more (corresponding to just over 200 account IDs, depending on how you encode the URI). 26 | - As of 2024-11-18, the `accountIdList` query parameter also supports the array format `accountIdList[]={accountID}`. The examples below show how to request club tags for multiple accounts using this approach. 27 | 28 | --- 29 | 30 | **Example request**: 31 | 32 | ```plain 33 | GET https://prod.trackmania.core.nadeo.online/accounts/clubTags/?accountIdList=5b4d42f4-c2de-407d-b367-cbff3fe817bc,45e5e4bc-d237-4e6e-8258-b60e8dc0c76a 34 | ``` 35 | 36 | **Example response**: 37 | 38 | ```json 39 | [ 40 | { 41 | "accountId": "45e5e4bc-d237-4e6e-8258-b60e8dc0c76a", 42 | "clubTag": "$A00X", 43 | "timestamp": "2024-03-30T05:54:17+00:00" 44 | }, 45 | { 46 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 47 | "clubTag": "$F05TSH", 48 | "timestamp": "2024-11-21T18:30:18+00:00" 49 | } 50 | ] 51 | ``` 52 | 53 | For multiple accounts, you may also send the `accountID` values as follows: 54 | 55 | ```plain 56 | GET https://prod.trackmania.core.nadeo.online/accounts/clubTags/?accountIdList[]=5b4d42f4-c2de-407d-b367-cbff3fe817bc&accountIdList[]=45e5e4bc-d237-4e6e-8258-b60e8dc0c76a 57 | ``` 58 | 59 | If an `accountId` is invalid, the response will contain an error message: 60 | 61 | ```json 62 | { 63 | "code": "C-AA-00-03", 64 | "correlation_id": "8646a82e689541aff09f34244d879d88", 65 | "message": "There was a validation error.", 66 | "info": { 67 | "accountIdList": "Invalid account id." 68 | } 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/core/accounts/display-names.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player display names 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /accounts/displayNames/?accountIdList={accountIdList} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: accountIdList 13 | type: string 14 | description: A comma-separated list of account IDs 15 | required: true 16 | max: 50 account IDs 17 | --- 18 | 19 |
20 | 21 | This endpoint has been removed on 2023-09-19. Use the [OAuth API endpoint](/oauth/reference/accounts/id-to-name) instead. 22 | 23 |
24 | 25 | Gets player display names from account IDs. 26 | 27 | --- 28 | 29 | **Remarks**: 30 | - This endpoint is only accessible with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). If you encounter `401` errors using a dedicated server account, switch to using a Ubisoft account. 31 | 32 | --- 33 | 34 | **Example request**: 35 | ```plain 36 | GET https://prod.trackmania.core.nadeo.online/accounts/displayNames/?accountIdList=5b4d42f4-c2de-407d-b367-cbff3fe817bc,7398eeb6-9b4e-44b8-a7a1-a2149955ac70 37 | ``` 38 | 39 | **Example response**: 40 | ```json 41 | [ 42 | { 43 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 44 | "displayName": "tooInfinite", 45 | "timestamp": "2020-07-01T15:05:34+00:00" 46 | }, 47 | { 48 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 49 | "displayName": "Miss-tm", 50 | "timestamp": "2020-06-05T19:32:19+00:00" 51 | } 52 | ] 53 | ``` 54 | 55 | If an `accountId` is invalid, the response will contain an error message: 56 | 57 | ```json 58 | { 59 | "code": "C-AA-00-03", 60 | "correlation_id": "4874aee1aee172e0afd7f605100f170a", 61 | "message": "There was a validation error.", 62 | "info": { 63 | "accountIdList": "Invalid account id." 64 | } 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/core/accounts/webidentities.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player webIdentities 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /webidentities/?accountIdList={accountIdList} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: accountIdList 13 | type: string 14 | description: A comma-separated list of account IDs 15 | required: true 16 | --- 17 | 18 | Gets player webIdentities from account IDs. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - The `timestamp` field is the creation date of the account - effectively the date when the account started playing Trackmania. 24 | - Due to the `ubiServices` and `uplay` providers being handled separately (potentially for historical reasons), there are typically two objects for each requested account. They will otherwise be identical. 25 | 26 | --- 27 | 28 | **Example request**: 29 | ```plain 30 | GET https://prod.trackmania.core.nadeo.online/webidentities/?accountIdList=5b4d42f4-c2de-407d-b367-cbff3fe817bc,7398eeb6-9b4e-44b8-a7a1-a2149955ac70 31 | ``` 32 | 33 | **Example response**: 34 | ```json 35 | [ 36 | { 37 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 38 | "provider": "ubiServices", 39 | "uid": "a59df3e8-6bff-48a2-98b6-801abf2a298e", 40 | "timestamp": "2020-07-01T15:05:34+00:00" 41 | }, 42 | { 43 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 44 | "provider": "uplay", 45 | "uid": "a59df3e8-6bff-48a2-98b6-801abf2a298e", 46 | "timestamp": "2020-07-01T15:05:34+00:00" 47 | }, 48 | { 49 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 50 | "provider": "ubiServices", 51 | "uid": "1ad088a9-4a99-43b7-a0a7-add68e3ac974", 52 | "timestamp": "2020-06-05T19:32:19+00:00" 53 | }, 54 | { 55 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 56 | "provider": "uplay", 57 | "uid": "1ad088a9-4a99-43b7-a0a7-add68e3ac974", 58 | "timestamp": "2020-06-05T19:32:19+00:00" 59 | } 60 | ] 61 | ``` 62 | 63 | If an `accountId` is invalid, the response will contain an error message: 64 | 65 | ```json 66 | { 67 | "code": "C-AA-00-03", 68 | "correlation_id": "16749c9cd157abf072db92319bdc51f1", 69 | "message": "There was a validation error.", 70 | "info": { 71 | "accountIdList": "Invalid account id." 72 | } 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/core/accounts/zones.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player zones 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /accounts/zones/?accountIdList={accountIdList} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: accountIdList 13 | type: string 14 | description: A comma-separated list of account IDs 15 | required: true 16 | --- 17 | 18 | Gets player zones from account IDs. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - This endpoint is only accessible with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). If you encounter `401` errors using a dedicated server account, switch to using a Ubisoft account. 24 | - This endpoint has no intrinsic limit on the number of account IDs requested, but it will return a `414` error if the request URI length is 8220 characters or more (corresponding to just over 200 account IDs, depending on how you encode the URI). 25 | - To translate `zoneId` values to names, reference the response from [the global zones endpoint](/core/meta/zones). 26 | - If you'd prefer a response that already contains zone names as well as the full zone hierarchy for a player, take a look at [the player trophies endpoint](/live/leaderboards/trophies). 27 | 28 | --- 29 | 30 | **Example request**: 31 | ```plain 32 | GET https://prod.trackmania.core.nadeo.online/accounts/zones/?accountIdList=5b4d42f4-c2de-407d-b367-cbff3fe817bc,7398eeb6-9b4e-44b8-a7a1-a2149955ac70 33 | ``` 34 | 35 | **Example response**: 36 | ```json 37 | [ 38 | { 39 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 40 | "timestamp": "2022-08-25T14:29:23+00:00", 41 | "zoneId": "301ff90f-7e13-11e8-8060-e284abfd2bc4" 42 | }, 43 | { 44 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 45 | "timestamp": "2020-06-05T19:32:46+00:00", 46 | "zoneId": "30209bf3-7e13-11e8-8060-e284abfd2bc4" 47 | } 48 | ] 49 | ``` 50 | 51 | If an `accountId` is invalid, the response will contain an error message: 52 | 53 | ```json 54 | { 55 | "code": "C-AA-00-03", 56 | "correlation_id": "8646a82e689541aff09f34244d879d88", 57 | "message": "There was a validation error.", 58 | "info": { 59 | "accountIdList": "Invalid account id." 60 | } 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/core/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Core API 3 | category: reference 4 | --- 5 | 6 | # Core API 7 | 8 | This is the main API the game talks to. Most of its endpoints require a token with the `NadeoServices` audience. 9 | 10 | Through this API, tokens for specific audiences can be requested (see [Authentication](/auth)). 11 | 12 | ## Deprecations 13 | 14 | - September 19th 2023: The [display names endpoint](/core/accounts/display-names) has been removed. To continue resolving `accountID` values to user names, it's recommended to use the relevant [OAuth API endpoint](/oauth/reference/accounts/id-to-name) instead. 15 | - July 1st 2024: The [map records endpoint](/core/records/map-records) has been deprecated. It is recommended to use the [map records v2 endpoint](/core/records/map-records-v2) as a direct replacement. 16 | 17 | ## Endpoints list 18 | 19 | There is [an endpoint that provides all of the available endpoints](/core/meta/routes). It does not require any authentication, and as such can be [viewed directly in the browser](https://prod.trackmania.core.nadeo.online/api/routes). 20 | 21 | Tokens authenticated through dedicated server accounts as described in [Authentication](/auth) can not use certain APIs. You can view which APIs those are by using the `usage` parameter. This means there are 3 endpoints to query: 22 | 23 | - `https://prod.trackmania.core.nadeo.online/api/routes` - Shows all available endpoints 24 | - `https://prod.trackmania.core.nadeo.online/api/routes?usage=Client` - Shows endpoints intended for clients 25 | - `https://prod.trackmania.core.nadeo.online/api/routes?usage=Server` - Shows endpoints intended for servers 26 | 27 | Dedicated server accounts do not have access to all accounts-related endpoints, which is why it's recommended to use the Ubisoft authentication method rather than the dedicated server method. 28 | 29 | ## Endpoints history 30 | 31 | We are tracking this endpoint API [through Github](https://github.com/openplanet-nl/core-api-tracking/commits/master) for changes Nadeo makes in real time. This is also pushed to [Discord](https://openplanet.dev/link/discord) in our `#announce` channel. 32 | -------------------------------------------------------------------------------- /docs/core/maps/authored.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get authored maps 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /maps/by-author 7 | 8 | audience: NadeoServices 9 | --- 10 | 11 | Gets all maps authored/created by the currently authenticated user. 12 | 13 | --- 14 | 15 | **Remarks**: 16 | 17 | - Because this endpoint only works for the currently authenticated user, it cannot be used by a dedicated server account. 18 | - Authored maps are defined as maps that were created/last saved by the current user - who initially uploaded/submitted the maps to Nadeo's servers is irrelevant for this endpoint. To get a list of maps uploaded by the current user, use [the submitted maps endpoint](/core/maps/submitted). 19 | 20 | --- 21 | 22 | **Example request**: 23 | 24 | ```plain 25 | GET https://prod.trackmania.core.nadeo.online/maps/by-author 26 | ``` 27 | 28 | **Example response**: 29 | 30 | ```json 31 | { 32 | "mapList": [ 33 | { 34 | "author": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 35 | "authorScore": 22410, 36 | "bronzeScore": 34000, 37 | "collectionName": "Stadium", 38 | "createdWithGamepadEditor": null, 39 | "createdWithSimpleEditor": null, 40 | "filename": "Rocky Fields.Map.Gbx", 41 | "goldScore": 24000, 42 | "isPlayable": true, 43 | "mapId": "6a2643a6-eb85-4bbb-82d9-70e3bea9347b", 44 | "mapStyle": "", 45 | "mapType": "TrackMania\\TM_Race", 46 | "mapUid": "AqzKeKIDr1VcY1esMt0fFtOgZXi", 47 | "name": "Rocky Fields", 48 | "silverScore": 27000, 49 | "submitter": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 50 | "timestamp": "2021-09-14T00:21:41+00:00", 51 | "fileUrl": "https://core.trackmania.nadeo.live/maps/6a2643a6-eb85-4bbb-82d9-70e3bea9347b/file", 52 | "thumbnailUrl": "https://core.trackmania.nadeo.live/maps/6a2643a6-eb85-4bbb-82d9-70e3bea9347b/thumbnail.jpg" 53 | }, 54 | ... 55 | { 56 | "author": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 57 | "authorScore": 27842, 58 | "bronzeScore": 42000, 59 | "collectionName": "Stadium", 60 | "createdWithGamepadEditor": null, 61 | "createdWithSimpleEditor": null, 62 | "filename": "Desert Hills.Map.Gbx", 63 | "goldScore": 30000, 64 | "isPlayable": true, 65 | "mapId": "0fbe8e92-b590-4e43-8372-43dbff65d3a7", 66 | "mapStyle": "", 67 | "mapType": "TrackMania\\TM_Race", 68 | "mapUid": "XKU9t4JixdOdp00Fyq2Bi5TFrB1", 69 | "name": "Desert Hills", 70 | "silverScore": 34000, 71 | "submitter": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 72 | "timestamp": "2021-09-13T22:32:46+00:00", 73 | "fileUrl": "https://core.trackmania.nadeo.live/maps/0fbe8e92-b590-4e43-8372-43dbff65d3a7/file", 74 | "thumbnailUrl": "https://core.trackmania.nadeo.live/maps/0fbe8e92-b590-4e43-8372-43dbff65d3a7/thumbnail.jpg" 75 | } 76 | ], 77 | "count": 13 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/core/maps/info-multiple.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map info (multiple) 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /maps/?mapIdList={mapIdList}&mapUidList={mapUidList} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: mapIdList 13 | type: string 14 | description: A comma-separated list of map IDs 15 | required: true 16 | - name: mapUidList 17 | type: string 18 | description: A comma-separated list of map UIDs 19 | required: true 20 | --- 21 | 22 | Gets information about multiple maps via their IDs/UIDs. 23 | 24 | --- 25 | 26 | **Remarks**: 27 | 28 | - The two parameters work the same way, but you can only use one of them at a time. 29 | - This endpoint has no intrinsic limit on the number of map IDs requested, but it will return a `414` error if the request URI length is 8220 characters or more (corresponding to just over 200 map IDs or almost 300 map UIDs, depending on how you encode the URI). 30 | 31 | --- 32 | 33 | **Example request**: 34 | 35 | ```plain 36 | GET https://prod.trackmania.core.nadeo.online/maps/?mapUidList=k45jQI6Y7XrPfe1T0hZhj4pKzY2,cmJJhEUYqesM6Tqpeds0lQudvOb 37 | ``` 38 | 39 | **Example response**: 40 | 41 | ```json 42 | [ 43 | { 44 | "author": "73eba009-a074-4439-916f-d25d7fa7bc1c", 45 | "authorScore": 102399, 46 | "bronzeScore": 154000, 47 | "collectionName": "Stadium", 48 | "createdWithGamepadEditor": false, 49 | "createdWithSimpleEditor": false, 50 | "filename": "Laserhawk_-_Megacity_Race.Map.Gbx", 51 | "goldScore": 109000, 52 | "isPlayable": true, 53 | "mapId": "a74716be-d124-4de1-87c2-834304ccef5b", 54 | "mapStyle": "", 55 | "mapType": "TrackMania\\TM_Race", 56 | "mapUid": "cmJJhEUYqesM6Tqpeds0lQudvOb", 57 | "name": "$i$a1bLaserhawk $fff- Megacity Race", 58 | "silverScore": 123000, 59 | "submitter": "7ad33388-641e-4497-b063-c88e75552645", 60 | "timestamp": "2023-10-23T17:05:25+00:00", 61 | "fileUrl": "https://core.trackmania.nadeo.live/storageObjects/6d67fafb-1be8-451a-91ca-661e019a9087", 62 | "thumbnailUrl": "https://core.trackmania.nadeo.live/storageObjects/70e82469-68b6-454a-a105-2af7c3279a4c.jpg" 63 | }, 64 | { 65 | "author": "7cd60a75-609a-4e64-b286-16f329878249", 66 | "authorScore": 26972, 67 | "bronzeScore": 41000, 68 | "collectionName": "Stadium", 69 | "createdWithGamepadEditor": false, 70 | "createdWithSimpleEditor": false, 71 | "filename": "SnowIsBack.Map.Gbx", 72 | "goldScore": 29000, 73 | "isPlayable": true, 74 | "mapId": "5546883f-b1ed-49e0-9397-55fc46f1d00c", 75 | "mapStyle": "", 76 | "mapType": "TrackMania\\TM_Race", 77 | "mapUid": "k45jQI6Y7XrPfe1T0hZhj4pKzY2", 78 | "name": "SnowIsBack", 79 | "silverScore": 33000, 80 | "submitter": "7cd60a75-609a-4e64-b286-16f329878249", 81 | "timestamp": "2023-11-21T16:50:01+00:00", 82 | "fileUrl": "https://core.trackmania.nadeo.live/storageObjects/5b244c36-da6d-45f2-bbd3-c97ed4b5efc0", 83 | "thumbnailUrl": "https://core.trackmania.nadeo.live/storageObjects/647ea926-6959-439e-a6e2-e7a78caa9529.jpg" 84 | } 85 | ] 86 | ``` 87 | 88 | If a `mapId` is invalid, the response will contain an error message: 89 | 90 | ```json 91 | { 92 | "code": "C-AA-00-03", 93 | "correlation_id": "10d26dadac018cccf1c9bcf138e3fb1c", 94 | "message": "There was a validation error.", 95 | "info": { 96 | "mapIdList": "Invalid uuid." 97 | } 98 | } 99 | ``` 100 | 101 | If a `mapUid` is invalid, that map will not be returned in the response. 102 | -------------------------------------------------------------------------------- /docs/core/maps/info.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map info 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /maps/{mapId} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | path: 12 | - name: mapId 13 | type: string 14 | description: The ID of the map 15 | required: true 16 | --- 17 | 18 | Gets information about a map via its ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - This endpoint only accepts `mapId`s - to get map information for a `mapUid` (or to translate `mapUid`s to `mapId`s), you can use the [map info (multiple) endpoint](/core/maps/info-multiple). 25 | 26 | --- 27 | 28 | **Example request**: 29 | 30 | ```plain 31 | GET https://prod.trackmania.core.nadeo.online/maps/d2b8a048-209d-4cfa-b5a4-bc3e3cab3566 32 | ``` 33 | 34 | **Example response**: 35 | 36 | ```json 37 | { 38 | "author": "d2372a08-a8a1-46cb-97fb-23a161d85ad0", 39 | "authorScore": 29089, 40 | "bronzeScore": 44000, 41 | "collectionName": "Stadium", 42 | "createdWithGamepadEditor": false, 43 | "createdWithSimpleEditor": false, 44 | "filename": "Spring 2024 - 01.Map.Gbx", 45 | "goldScore": 31000, 46 | "isPlayable": true, 47 | "mapId": "d2b8a048-209d-4cfa-b5a4-bc3e3cab3566", 48 | "mapStyle": "", 49 | "mapType": "TrackMania\\TM_Race", 50 | "mapUid": "yQ4ktCXu3SAxyRx9gar8hj7kVBb", 51 | "name": "Spring 2024 - 01", 52 | "silverScore": 35000, 53 | "submitter": "d2372a08-a8a1-46cb-97fb-23a161d85ad0", 54 | "timestamp": "2024-03-27T10:40:03+00:00", 55 | "fileUrl": "https://core.trackmania.nadeo.live/storageObjects/69ff7efb-010e-43db-8233-11d119aa0499", 56 | "thumbnailUrl": "https://core.trackmania.nadeo.live/storageObjects/ea9128eb-dabb-4b08-b9d1-37adb25b41b2.jpg" 57 | } 58 | ``` 59 | 60 | If the `mapId` is invalid, the response will contain an error message: 61 | 62 | ```json 63 | { 64 | "code": "C-AA-00-03", 65 | "correlation_id": "e88e55743a177f17d32d963070057078", 66 | "message": "There was a validation error.", 67 | "info": ["mapId: Invalid uuid."] 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/core/maps/set-vote.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Set map vote 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: POST 6 | route: /maps/{mapUid}/votes 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | path: 12 | - name: mapUid 13 | type: string 14 | description: The UID of the map 15 | required: true 16 | 17 | --- 18 | 19 | The request body contains the vote value: 20 | 21 | ```json 22 | { 23 | "vote": 1 24 | } 25 | ``` 26 | 27 | --- 28 | 29 | Sets a like/dislike vote for a map as the currently authenticated user. 30 | 31 | --- 32 | 33 | **Remarks**: 34 | 35 | - Because this endpoint only works for the currently authenticated user, it cannot be used by a dedicated server account. 36 | - The `vote` field can be set to `-1` for a dislike, or `1` for a like. `0` can be used to unset the vote. 37 | 38 | --- 39 | 40 | **Example request**: 41 | 42 | ```plain 43 | POST https://prod.trackmania.core.nadeo.online/maps/ytKTrmjtk352Ou_7IE3xHWhyj2a/votes 44 | ``` 45 | 46 | ```json 47 | { 48 | "vote": 1 49 | } 50 | ``` 51 | 52 | **Example response**: 53 | 54 | ```plain 55 | null 56 | ``` 57 | 58 | If the `mapUid` is invalid, the response will contain an error message: 59 | 60 | ```json 61 | { 62 | "code": "C-AA-00-03", 63 | "correlation_id": "127bd2d9070bad276a1422d9268c2d10", 64 | "message": "There was a validation error.", 65 | "info": [ 66 | "mapUid: This value is too long. It should have 27 characters or less." 67 | ] 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/core/maps/submitted.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get submitted maps 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /maps/by-submitter 7 | 8 | audience: NadeoServices 9 | --- 10 | 11 | Gets all maps submitted/uploaded by the currently authenticated user. 12 | 13 | --- 14 | 15 | **Remarks**: 16 | 17 | - Because this endpoint only works for the currently authenticated user, it cannot be used by a dedicated server account. 18 | - Submitted maps are defined as maps that were uploaded by the current user - who initially authored/created the maps is irrelevant for this endpoint. To get a list of maps authored by the current user, use [the authored maps endpoint](/core/maps/authored). 19 | 20 | --- 21 | 22 | **Example request**: 23 | 24 | ```plain 25 | GET https://prod.trackmania.core.nadeo.online/maps/by-submitter 26 | ``` 27 | 28 | **Example response**: 29 | 30 | ```json 31 | { 32 | "mapList": [ 33 | { 34 | "author": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 35 | "authorScore": 27842, 36 | "bronzeScore": 42000, 37 | "collectionName": "Stadium", 38 | "createdWithGamepadEditor": null, 39 | "createdWithSimpleEditor": null, 40 | "filename": "Desert Hills.Map.Gbx", 41 | "goldScore": 30000, 42 | "isPlayable": true, 43 | "mapId": "0fbe8e92-b590-4e43-8372-43dbff65d3a7", 44 | "mapStyle": "", 45 | "mapType": "TrackMania\\TM_Race", 46 | "mapUid": "XKU9t4JixdOdp00Fyq2Bi5TFrB1", 47 | "name": "Desert Hills", 48 | "silverScore": 34000, 49 | "submitter": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 50 | "timestamp": "2021-09-13T22:32:46+00:00", 51 | "fileUrl": "https://core.trackmania.nadeo.live/maps/0fbe8e92-b590-4e43-8372-43dbff65d3a7/file", 52 | "thumbnailUrl": "https://core.trackmania.nadeo.live/maps/0fbe8e92-b590-4e43-8372-43dbff65d3a7/thumbnail.jpg" 53 | }, 54 | ... 55 | { 56 | "author": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 57 | "authorScore": 22410, 58 | "bronzeScore": 34000, 59 | "collectionName": "Stadium", 60 | "createdWithGamepadEditor": null, 61 | "createdWithSimpleEditor": null, 62 | "filename": "Rocky Fields.Map.Gbx", 63 | "goldScore": 24000, 64 | "isPlayable": true, 65 | "mapId": "6a2643a6-eb85-4bbb-82d9-70e3bea9347b", 66 | "mapStyle": "", 67 | "mapType": "TrackMania\\TM_Race", 68 | "mapUid": "AqzKeKIDr1VcY1esMt0fFtOgZXi", 69 | "name": "Rocky Fields", 70 | "silverScore": 27000, 71 | "submitter": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 72 | "timestamp": "2021-09-14T00:21:41+00:00", 73 | "fileUrl": "https://core.trackmania.nadeo.live/maps/6a2643a6-eb85-4bbb-82d9-70e3bea9347b/file", 74 | "thumbnailUrl": "https://core.trackmania.nadeo.live/maps/6a2643a6-eb85-4bbb-82d9-70e3bea9347b/thumbnail.jpg" 75 | } 76 | ], 77 | "count": 15 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/core/maps/vote.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map vote 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /maps/{mapUid}/votes 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | path: 12 | - name: mapUid 13 | type: string 14 | description: The UID of the map 15 | required: true 16 | 17 | --- 18 | 19 | Gets the currently authenticated user's vote for a map. 20 | 21 | --- 22 | 23 | **Remarks**: 24 | 25 | - Because this endpoint only works for the currently authenticated user, it cannot be used by a dedicated server account. 26 | - The `vote` field in the response can be `-1` for a dislike, or `1` for a like. `0` indicates the user has not voted or has removed a previous vote again. 27 | - The `voteDate` field in the response contains the day of the vote (i.e. the last change to the given map's vote), but not an exact timestamp. 28 | 29 | --- 30 | 31 | **Example request**: 32 | 33 | ```plain 34 | GET https://prod.trackmania.core.nadeo.online/maps/ytKTrmjtk352Ou_7IE3xHWhyj2a/votes 35 | ``` 36 | 37 | **Example response**: 38 | 39 | ```json 40 | { 41 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 42 | "mapUid": "ytKTrmjtk352Ou_7IE3xHWhyj2a", 43 | "vote": 1, 44 | "voteDate": "2024-12-24T00:00:00+00:00" 45 | } 46 | ``` 47 | 48 | If the `mapUid` is invalid, the response will contain an error message: 49 | 50 | ```json 51 | { 52 | "code": "C-AA-00-03", 53 | "correlation_id": "60e8a3c2c6233f9408e315b31799b56b", 54 | "message": "There was a validation error.", 55 | "info": [ 56 | "mapUid: This value is too long. It should have 27 characters or less." 57 | ] 58 | } 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/core/meta/routes.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get API routes 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /api/routes?usage={usage} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: usage 13 | type: string 14 | description: The type of relevant usage (see below for accepted values) 15 | required: true 16 | 17 | --- 18 | 19 | Gets all available routes on the Core API. 20 | 21 | --- 22 | 23 | **Remarks**: 24 | - There are two allowed values for the `usage` parameter: `Client` and `Server`. 25 | 26 | --- 27 | 28 | **Example request**: 29 | ```plain 30 | GET https://prod.trackmania.core.nadeo.online/api/routes?usage=Client 31 | ``` 32 | 33 | **Example response**: 34 | ```json 35 | { 36 | "nadeoservices_storage_object_content_url_redirect": { 37 | "method": "GET", 38 | "path": "/storageObjects/{storageObjectId}" 39 | }, 40 | "nadeoservices_driver_bot_list_add": { 41 | "method": "POST", 42 | "path": "/bots/drivers/" 43 | }, 44 | ... 45 | "nadeoservices_account_zone_set": { 46 | "method": "PUT", 47 | "path": "/accounts/{accountId}/zone" 48 | }, 49 | "nadeoservices_zone_list_get": { 50 | "method": "GET", 51 | "path": "/zones/" 52 | } 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/core/meta/zones.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get zones 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /zones/ 7 | 8 | audience: NadeoServices 9 | 10 | --- 11 | 12 | Gets all available zones. 13 | 14 | --- 15 | 16 | **Example request**: 17 | ```plain 18 | GET https://prod.trackmania.core.nadeo.online/zones/ 19 | ``` 20 | 21 | **Example response**: 22 | ```json 23 | [ 24 | { 25 | "icon": "file://Media/Flags/Aachen.jpg", 26 | "name": "Aachen", 27 | "parentId": "30200d6a-7e13-11e8-8060-e284abfd2bc4", 28 | "timestamp": "2022-11-14T11:19:00+00:00", 29 | "zoneId": "30200df4-7e13-11e8-8060-e284abfd2bc4" 30 | }, 31 | ... 32 | { 33 | "icon": "file://Media/Flags/UKR.dds", 34 | "name": "Ukraine", 35 | "parentId": "301e2106-7e13-11e8-8060-e284abfd2bc4", 36 | "timestamp": "2022-11-14T11:19:00+00:00", 37 | "zoneId": "3022a07d-7e13-11e8-8060-e284abfd2bc4" 38 | }, 39 | ... 40 | ] 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/core/records/map-record.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get record by ID 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /mapRecords/{mapRecordId} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | path: 12 | - name: mapRecordId 13 | type: string 14 | description: A mapRecord ID 15 | required: true 16 | --- 17 | 18 | Gets a single map record using its primary identifier. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - This endpoint only accepts a `mapRecordId` - to retrieve it, you can use the [map records endpoint](/core/records/map-records). 25 | - If the map author has set a secret threshold score for their map, this endpoint will not return an actual `time` value. Instead, the response will contain `4294967295` in the `time` field. Additionally, the `url` link will result in a `403` error when requested. 26 | 27 | --- 28 | 29 | **Example request**: 30 | 31 | ```plain 32 | GET https://prod.trackmania.core.nadeo.online/mapRecords/ade1de4c-dd53-4a65-9d9b-89c5b1b9fa44 33 | ``` 34 | 35 | **Example response**: 36 | 37 | ```json 38 | { 39 | "accountId": "04dd686d-0d2e-4c4c-bd37-81d57ae47656", 40 | "filename": "Replays\\Downloaded\\37852772-23c5-40cb-8106-9fdae43efa6f_04dd686d-0d2e-4c4c-bd37-81d57ae47656_(0'45''37).replay.gbx", 41 | "gameMode": "TimeAttack", 42 | "gameModeCustomData": "", 43 | "mapId": "37852772-23c5-40cb-8106-9fdae43efa6f", 44 | "mapRecordId": "ade1de4c-dd53-4a65-9d9b-89c5b1b9fa44", 45 | "medal": 1, 46 | "recordScore": { 47 | "respawnCount": 4294967295, 48 | "score": 0, 49 | "time": 45376 50 | }, 51 | "removed": false, 52 | "scopeId": null, 53 | "scopeType": "PersonalBest", 54 | "timestamp": "2020-07-12T01:54:41+02:00", 55 | "url": "https://prod.trackmania.core.nadeo.online/storageObjects/317832fc-7576-4a65-954e-b0eb390a7372" 56 | } 57 | ``` 58 | 59 | If the `mapRecordId` is invalid, the response will contain an error message: 60 | 61 | ```json 62 | { 63 | "code": "C-AA-00-03", 64 | "correlation_id": "8ed109aa5aff42c0b2606c51a43bbf15", 65 | "message": "There was a validation error.", 66 | "info": { 67 | "mapRecordId": "Invalid uuid." 68 | } 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/core/skins/equipped.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get equipped skins 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /accounts/skins?accountIdList={accountIdList} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | query: 12 | - name: accountIdList 13 | type: string 14 | description: Comma-separated list of account IDs 15 | required: true 16 | --- 17 | 18 | Gets the equipped skins data for the requested users. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - This endpoint only returns a skin's identifier - if you need to retrieve the actual skin information, you can use [the skin info endpoint](/core/skins/info). 25 | - This endpoint is only accessible with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). If you encounter `401` errors using a dedicated server account, switch to using a Ubisoft account. 26 | 27 | --- 28 | 29 | **Example request**: 30 | 31 | ```plain 32 | GET https://prod.trackmania.core.nadeo.online/accounts/skins/?accountIdList=5b4d42f4-c2de-407d-b367-cbff3fe817bc,da4642f9-6acf-43fe-88b6-b120ff1308ba 33 | ``` 34 | 35 | **Example response**: 36 | 37 | ```json 38 | [ 39 | { 40 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 41 | "skinId": "dca3a74a-acf5-4780-8842-15ba80c3b673", 42 | "skinType": "Models/CarSport", 43 | "timestamp": "2023-06-01T15:18:02+00:00" 44 | }, 45 | { 46 | "accountId": "da4642f9-6acf-43fe-88b6-b120ff1308ba", 47 | "skinId": "28ea4f72-7a5b-42b2-a082-cc6c59616918", 48 | "skinType": "Models/CarSport", 49 | "timestamp": "2023-05-25T22:16:09+00:00" 50 | } 51 | ] 52 | ``` 53 | 54 | If an `accountId` is invalid, the response will contain an error message (along with status code `400`): 55 | 56 | ```json 57 | { 58 | "code": "C-AA-00-03", 59 | "correlation_id": "2b43d7ab9ac81778cdae282cd5644fe4", 60 | "message": "There was a validation error.", 61 | "info": { 62 | "accountIdList": "Invalid account id." 63 | } 64 | } 65 | ``` 66 | 67 | If an `accountId` belongs to a user without an equipped skin, that user will be omitted from the results. 68 | -------------------------------------------------------------------------------- /docs/core/skins/favorites.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get favorited skins 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /accounts/{accountId}/skins/favorites 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | path: 12 | - name: accountId 13 | type: string 14 | description: The account ID of the authenticated user 15 | required: true 16 | --- 17 | 18 | Gets the favorited/garage skins data for the currently authenticated user. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - Because this endpoint only works for the currently authenticated user, it cannot be used by a dedicated server account. 24 | - The `timestamp` value for each skin corresponds to when it got added to the user's favorites. 25 | - This endpoint only returns a skin's identifier - if you need to retrieve the actual skin information, you can use [the skin info endpoint](/core/skins/info). 26 | 27 | --- 28 | 29 | **Example request**: 30 | ```plain 31 | GET https://prod.trackmania.core.nadeo.online/accounts/5b4d42f4-c2de-407d-b367-cbff3fe817bc/skins/favorites/ 32 | ``` 33 | 34 | **Example response**: 35 | ```json 36 | [ 37 | { 38 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 39 | "skinId": "148c3dee-baf8-499f-8f63-757f46a482da", 40 | "timestamp": "2021-05-18T16:48:16+00:00" 41 | }, 42 | ... 43 | { 44 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 45 | "skinId": "f056c154-b408-44af-a5e3-8919cc7f3689", 46 | "timestamp": "2022-02-07T16:11:52+00:00" 47 | } 48 | ] 49 | ``` 50 | 51 | If the `accountId` is invalid, the response will contain an error message (along with status code `400`): 52 | 53 | ```json 54 | { 55 | "code": "C-AA-00-03", 56 | "correlation_id": "ae97862a4d59402deb5f5cdc6a92b643", 57 | "message": "There was a validation error.", 58 | "info": { 59 | "accountId": "Invalid account id." 60 | } 61 | } 62 | ``` 63 | 64 | If the `accountId` belongs to a user that's not currently authenticated, the response will contain an error message (along with status `403`): 65 | 66 | ```json 67 | { 68 | "code": "C-AA-00-05", 69 | "correlation_id": "6ec3b5614cb3260d39ff279db231ff83", 70 | "message": "Forbidden." 71 | } 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/core/skins/info.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get skin info 3 | 4 | url: https://prod.trackmania.core.nadeo.online 5 | method: GET 6 | route: /skins/{skinId} 7 | 8 | audience: NadeoServices 9 | 10 | parameters: 11 | path: 12 | - name: skinId 13 | type: string 14 | description: The requested skin's ID 15 | required: true 16 | --- 17 | 18 | Gets the skin information for the requested skin ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - This endpoint is only accessible with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). If you encounter `401` errors using a dedicated server account, switch to using a Ubisoft account. 24 | 25 | --- 26 | 27 | **Example request**: 28 | ```plain 29 | GET https://prod.trackmania.core.nadeo.online/skins/dca3a74a-acf5-4780-8842-15ba80c3b673 30 | ``` 31 | 32 | **Example response**: 33 | ```json 34 | { 35 | "creatorId": "3468343f-bc7f-4ddd-938f-0f118d13cdc9", 36 | "checksum": "50768A804AB4382B90A744C401B50A6C245B5CA5C707F6C7DE9ADA295A70D35F", 37 | "filename": "ProffCarbon.zip", 38 | "fileOptimizedUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/4dc83a53-033f-468a-a789-1e9893d0b612", 39 | "fileUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/b2324d14-ceaf-4e26-8865-0fe4e61f5249", 40 | "skinDisplayName": "ProffCarbon", 41 | "skinId": "dca3a74a-acf5-4780-8842-15ba80c3b673", 42 | "skinName": "Skins\\Models\\CarSport\\ProffCarbon.zip", 43 | "skinType": "Models/CarSport", 44 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/e68723fa-9929-42b0-9ace-8fdf14f66a36.tga", 45 | "timestamp": "2020-11-29T21:00:10+00:00" 46 | } 47 | ``` 48 | 49 | If the `skinId` is invalid, the response will contain an error message (along with status code `400`): 50 | 51 | ```json 52 | { 53 | "code": "C-AA-00-03", 54 | "correlation_id": "4680da87c7ec7568901dfa1dbbc424e8", 55 | "message": "There was a validation error.", 56 | "info": { 57 | "skinId": "Invalid uuid." 58 | } 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | pages: 3 | - glossary 4 | dirs: 5 | - auth 6 | - core 7 | - live 8 | - meet 9 | roots: 10 | - oauth 11 | 12 | --- 13 | 14 | # Home 15 | 16 | This is the (unofficial) documentation for the Trackmania (2020) game APIs, documented by the Openplanet community. It was created to be a central place for the most up-to-date documentation for the most used APIs in the game. 17 | 18 | If you're not familiar with the authentication flow for any of the game APIs, check out [the Authentication guide](/auth). 19 | 20 | The documentation is structured by the three main API domains, each of which cover a slightly different area of the game: 21 | 22 | - [**Core**](/core): The main API that allows the game to authenticate to all other APIs, but also has many other tasks relating to the game's native functionality. This can also be considered the game's masterserver. 23 | - [**Live**](/live): The live API is mostly used for leaderboards and other live content such as campaigns, rooms, clubs and Tracks of the Day. 24 | - [**Meet**](/meet): The meet API is used for competitions, matchmaking and other match infrastructure tasks. 25 | 26 | As of July 2023, the _Competition_, _Matchmaking_ and _Club_ domains have been merged into the **Meet** API. The old domains will stay functional for a while, but it's highly recommended to migrate off of them as soon as possible. 27 | 28 | Additionally, [the OAuth documentation](/oauth/summary) contains information on integrating external applications with the official Trackmania OAuth API. Note that this API is completely separate from the main game APIs, and authentication flows are not compatible between the two. 29 | 30 | ## Responsible usage 31 | 32 | All game APIs are to be used responsibly. Nadeo/Ubisoft **can and will ban your accounts/IPs** if they detect any disruptive (sending too many requests too fast) or any other malicious behavior. 33 | 34 | There are no official rate limits, but Nadeo developers have said in the past that the upper limit of acceptable usage is at about **two requests/second for short-term bursts**. If you are planning to send a lot of requests throughout a long period of time (for bulk operations or semi-live monitoring), you should reduce the frequency of requests. 35 | 36 | Make sure you send along a useful `User-Agent` header that includes what your project is, who you are (your name or some username/handle), and how to contact you (your email address). For example: 37 | 38 | ```plain 39 | My awesome leaderboard / @miss / miss@example.com 40 | ``` 41 | 42 | To report a potential security concern directly to Nadeo/Ubisoft, send an email to . 43 | 44 | ## API status 45 | 46 | There is an [unofficial status page](https://trackmania-status.cdn.ubi.com/status.html) for the main Web Services APIs. The same data is also available [in JSON format](https://trackmania-status.cdn.ubi.com/status.json). 47 | 48 | Note that these resources may not always accurately reflect unexpected outages and issues with specific endpoints - they're primarily used for communicating planned maintenance periods. 49 | 50 | ## Helpful community projects 51 | 52 | These useful projects are maintained by Trackmania community members - check them out if you're looking for starting points or convenient ways to test/utilize Nadeo's APIs. 53 | 54 | - [nadeo-api-bruno](https://github.com/davidbmaier/nadeo-api-bruno) is a collection of commonly-used endpoints for [Bruno](https://www.usebruno.com/) (maintained by **tooInfinite**) 55 | - [nadeo-api](https://pypi.org/project/nadeo-api/) is a Nadeo API **Python** library (maintained by **Ezio416**) 56 | - [nadeo-api-rs](https://crates.io/crates/nadeo-api-rs) is a Nadeo API **Rust** library (maintained by **XertroV**) 57 | - [ManiaAPI.NadeoAPI](https://www.nuget.org/packages/ManiaAPI.NadeoAPI) is a Nadeo API **C#** library (maintained by **BigBang1112**) 58 | 59 | ## Contributing and support 60 | 61 | This is a community project that's actively being worked on - as such, the documentation is not complete in some areas. Don't hesitate to [reach out and get involved on Github](https://github.com/openplanet-nl/nadeoapi-docs), or [talk about the API on Discord](https://openplanet.dev/link/discord). 62 | -------------------------------------------------------------------------------- /docs/live/campaigns/campaigns-v2.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get seasonal campaigns (v2) 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/campaign/official?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of campaigns to retrieve 15 | required: true 16 | - name: offset 17 | type: integer 18 | description: The number of campaigns to skip (looking backwards from the current campaign) 19 | required: true 20 | --- 21 | 22 | Gets official seasonal campaigns. 23 | 24 | --- 25 | 26 | **Remarks**: 27 | 28 | - This endpoint serves the same purpose as the [Get seasonal campaigns](/live/campaigns/campaigns) endpoint, but the response data model is slightly different. 29 | 30 | --- 31 | 32 | **Example request**: 33 | 34 | ```plain 35 | GET https://live-services.trackmania.nadeo.live/api/campaign/official?offset=0&length=1 36 | ``` 37 | 38 | **Example response**: 39 | 40 | ```json 41 | { 42 | "itemCount": 18, 43 | "campaignList": [ 44 | { 45 | "id": 77963, 46 | "seasonUid": "402f721f-65ca-4975-9eb0-afa753561a8a", 47 | "name": "Fall 2024", 48 | "useCase": 0, 49 | "clubId": 0, 50 | "startTimestamp": 1727794800, 51 | "endTimestamp": 1735747200, 52 | "rankingSentTimestamp": null, 53 | "year": -1, 54 | "week": -1, 55 | "day": -1, 56 | "monthYear": -1, 57 | "month": -1, 58 | "monthDay": -1, 59 | "playlist": [ 60 | { 61 | "id": 926443, 62 | "position": 0, 63 | "mapUid": "rw7jr8WlTrYor0vN0A0PiKzgg78" 64 | }, 65 | ... 66 | { 67 | "id": 926467, 68 | "position": 24, 69 | "mapUid": "End5ikYJa8pgN8RI347E6l4i7lg" 70 | } 71 | ], 72 | "editionTimestamp": 1727082440 73 | } 74 | ], 75 | "nextRequestTimestamp": 1735747200, 76 | "relativeNextRequest": 704811 77 | } 78 | ``` 79 | 80 | If the campaign does not exist, the response will show an empty list: 81 | 82 | ```json 83 | { 84 | "itemCount": 18, 85 | "campaignList": [], 86 | "nextRequestTimestamp": 1735747200, 87 | "relativeNextRequest": 704825 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/live/campaigns/map-info.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get campaign/TOTD info for a map 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/campaign/map/{mapUid} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: mapUid 13 | type: string 14 | description: The UID of the map 15 | required: true 16 | --- 17 | 18 | Gets information about a map's official campaign/TOTD status. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - This endpoint does not provide any information about whether a map is part of any club campaigns. 24 | - The `officialMaps` field in the response is a list of all maps' `mapUid`s that were part of the same seasonal campaign as the requested map. 25 | - The `totdMaps` field in the response is a list of all maps' `mapUid`s that were part of the same week as the requested map. 26 | 27 | --- 28 | 29 | **Example request**: 30 | ```plain 31 | GET https://live-services.trackmania.nadeo.live/api/campaign/map/ClF9ty2T55DZq4a8619TMvke5P7 32 | ``` 33 | 34 | **Example response**: 35 | ```json 36 | { 37 | "officialYear": -1, 38 | "season": -1, 39 | "officialMaps": [], 40 | "totdYear": 2023, 41 | "week": 3, 42 | "totdMaps": [ 43 | "cfQYjTzrRAyXctfkl1MH0JtmRWc", 44 | "ClF9ty2T55DZq4a8619TMvke5P7", 45 | "ADj5UCjoxJCppggf6SsVqXi3kM", 46 | "yRo4EXsukowHwkDb0uQjXAEH7sg", 47 | "U2NfU6SMIgllFpoYmE85ZbHteo", 48 | "ZAs2YmLo00RT2cnMnG11wxvcnZi", 49 | "eE4PFcW4yhboOeNVEAi0esxOswe" 50 | ] 51 | } 52 | ``` 53 | 54 | Example response if the requested map does not exist or is not part of any campaigns or TOTDs: 55 | 56 | ```json 57 | { 58 | "officialYear": -1, 59 | "season": -1, 60 | "officialMaps": [], 61 | "totdYear": -1, 62 | "week": -1, 63 | "totdMaps": [] 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/live/campaigns/totds.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get TOTDs/Royal maps 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/campaign/month?length={length}&offset={offset}&royal={royal} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of months to retrieve 15 | required: true 16 | - name: offset 17 | type: integer 18 | description: The number of months to skip (looking backwards from the current month) 19 | required: true 20 | - name: royal 21 | type: boolean 22 | description: Whether to return maps for the Royal mode instead of TOTDs 23 | require: false 24 | --- 25 | 26 | Gets Tracks of the Day (or Royal maps) by month. 27 | 28 | --- 29 | 30 | **Example request**: 31 | ```plain 32 | GET https://live-services.trackmania.nadeo.live/api/token/campaign/month?offset=7&length=1 33 | ``` 34 | 35 | **Example response**: 36 | ```json 37 | { 38 | "monthList": [ 39 | { 40 | "year": 2021, 41 | "month": 12, 42 | "lastDay": 31, 43 | "days": [ 44 | { 45 | "campaignId": 18255, 46 | "mapUid": "CFI34MJLLF0M88pCmn1WHTSd6K9", 47 | "day": 2, 48 | "monthDay": 1, 49 | "seasonUid": "ee58b4e5-a7f0-41de-a8dd-e4744b009ab2", 50 | "leaderboardGroup": null, 51 | "startTimestamp": 1638381600, 52 | "endTimestamp": 1638468000, 53 | "relativeStart": -20469159, 54 | "relativeEnd": -20382759 55 | }, 56 | ... 57 | { 58 | "campaignId": 18865, 59 | "mapUid": "mijbrgeyRo6XyjlulEE6QhZSQNm", 60 | "day": 4, 61 | "monthDay": 31, 62 | "seasonUid": "90769a06-30f6-4980-83eb-b046e15c111b", 63 | "leaderboardGroup": null, 64 | "startTimestamp": 1640973600, 65 | "endTimestamp": 1641060000, 66 | "relativeStart": -17877159, 67 | "relativeEnd": -17790759 68 | } 69 | ], 70 | "media": { 71 | "buttonBackgroundUrl": "", 72 | "buttonForegroundUrl": "", 73 | "decalUrl": "", 74 | "popUpBackgroundUrl": "", 75 | "popUpImageUrl": "", 76 | "liveButtonBackgroundUrl": "", 77 | "liveButtonForegroundUrl": "" 78 | } 79 | } 80 | ], 81 | "itemCount": 25, 82 | "nextRequestTimestamp": 1658854800, 83 | "relativeNextRequest": 4041 84 | } 85 | ``` 86 | 87 | If the month does not exist, the response will show an empty list: 88 | 89 | ```json 90 | { 91 | "monthList": [ 92 | 93 | ], 94 | "itemCount": 26, 95 | "nextRequestTimestamp": 1661274000, 96 | "relativeNextRequest": 77366 97 | } 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/live/campaigns/weekly-shorts.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get weekly shorts 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/campaign/weekly-shorts?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of weekly shorts campaigns to retrieve 15 | required: true 16 | - name: offset 17 | type: integer 18 | description: The number of weekly shorts campaigns to skip (looking backwards from the current campaign) 19 | required: true 20 | --- 21 | 22 | Gets weekly shorts campaigns. 23 | 24 | --- 25 | 26 | **Example request**: 27 | 28 | ```plain 29 | GET https://live-services.trackmania.nadeo.live/api/campaign/weekly-shorts?offset=0&length=1 30 | ``` 31 | 32 | **Example response**: 33 | 34 | ```json 35 | { 36 | "itemCount": 2, 37 | "campaignList": [ 38 | { 39 | "id": 83986, 40 | "seasonUid": "d63cac8c-a3e3-4320-b58b-4ae85bfc4987", 41 | "name": "Week 2", 42 | "useCase": 5, 43 | "clubId": 0, 44 | "startTimestamp": 1734886800, 45 | "endTimestamp": 1735491600, 46 | "rankingSentTimestamp": null, 47 | "year": 2024, 48 | "week": 2, 49 | "day": -1, 50 | "monthYear": -1, 51 | "month": -1, 52 | "monthDay": -1, 53 | "playlist": [ 54 | { 55 | "id": 999650, 56 | "position": 0, 57 | "mapUid": "v97FfwztlgncAiVxDSyOI8FMmCh" 58 | }, 59 | { 60 | "id": 999651, 61 | "position": 1, 62 | "mapUid": "PUZW_cmHUVuX6S7Sg5v5AUxBxP1" 63 | }, 64 | { 65 | "id": 999652, 66 | "position": 2, 67 | "mapUid": "ye9RBZObEfQaVvPRwvL32qCFEZm" 68 | }, 69 | { 70 | "id": 999653, 71 | "position": 3, 72 | "mapUid": "3EoC4KP470YW30_9aLVMsO5TsF7" 73 | }, 74 | { 75 | "id": 999654, 76 | "position": 4, 77 | "mapUid": "8qvIspNnTHFWK7S1OlGsokE9Ibe" 78 | } 79 | ], 80 | "editionTimestamp": 1734346663 81 | } 82 | ], 83 | "nextRequestTimestamp": 1735491600, 84 | "relativeNextRequest": 449802 85 | } 86 | ``` 87 | 88 | If the campaign does not exist, the response will show an empty list: 89 | 90 | ```json 91 | { 92 | "itemCount": 2, 93 | "campaignList": [], 94 | "nextRequestTimestamp": 1735491600, 95 | "relativeNextRequest": 449777 96 | } 97 | ``` 98 | -------------------------------------------------------------------------------- /docs/live/clubs/campaign-by-id.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club campaign by ID 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/{clubID}/campaign/{campaignID} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: clubID 13 | type: integer 14 | description: The ID of the club the campaign belongs to 15 | required: true 16 | - name: campaignID 17 | type: integer 18 | description: The ID of the campaign to be requested 19 | required: true 20 | --- 21 | 22 | Gets the details of a specific club campaign. 23 | 24 | --- 25 | 26 | **Remarks**: 27 | 28 | - As of 2024-01-17, this endpoint's response links to `.dds` media files by default, while several scaled `.png` versions are available using separate fields (see example below for reference). 29 | 30 | --- 31 | 32 | **Example request**: 33 | 34 | ```plain 35 | GET https://live-services.trackmania.nadeo.live/api/token/club/19489/campaign/28446 36 | ``` 37 | 38 | **Example response**: 39 | 40 | ```json 41 | { 42 | "clubDecalUrl": "", 43 | "campaignId": 28446, 44 | "activityId": 302134, 45 | "campaign": { 46 | "id": 28446, 47 | "seasonUid": "NLS-oCLUEcsEL1c45ePnhFnW4wZv4vkd1VKijYY", 48 | "name": "Icy Summer 2022", 49 | "color": "", 50 | "useCase": 2, 51 | "clubId": 19489, 52 | "leaderboardGroupUid": "NLS-oCLUEcsEL1c45ePnhFnW4wZv4vkd1VKijYY", 53 | "publicationTimestamp": 1658480776, 54 | "startTimestamp": 1658480776, 55 | "endTimestamp": 0, 56 | "rankingSentTimestamp": null, 57 | "year": -1, 58 | "week": -1, 59 | "day": -1, 60 | "monthYear": -1, 61 | "month": -1, 62 | "monthDay": -1, 63 | "published": true, 64 | "playlist": [ 65 | { 66 | "id": 314741, 67 | "position": 0, 68 | "mapUid": "tknxMmzHqPOImrE7FWNzzdvCia2" 69 | }, 70 | ... 71 | { 72 | "id": 314857, 73 | "position": 24, 74 | "mapUid": "i5dupTLKB6AquA1yhsNp40SjXF2" 75 | } 76 | ], 77 | "latestSeasons": [ 78 | { 79 | "uid": "NLS-oCLUEcsEL1c45ePnhFnW4wZv4vkd1VKijYY", 80 | "name": "Icy Summer 2022", 81 | "startTimestamp": 1658480776, 82 | "endTimestamp": 0, 83 | "relativeStart": -47124886, 84 | "relativeEnd": 0, 85 | "campaignId": 28446, 86 | "active": true 87 | } 88 | ], 89 | "categories": [ 90 | { 91 | "position": 0, 92 | "length": 5, 93 | "name": "Icy Summer 2022" 94 | } 95 | ], 96 | "media": { 97 | "buttonBackgroundUrl": "", 98 | "buttonForegroundUrl": "", 99 | "decalUrl": "", 100 | "popUpBackgroundUrl": "", 101 | "popUpImageUrl": "", 102 | "liveButtonBackgroundUrl": "", 103 | "liveButtonForegroundUrl": "" 104 | }, 105 | "editionTimestamp": 1658531133 106 | }, 107 | "popularityLevel": 0, 108 | "publicationTimestamp": 1658480776, 109 | "creationTimestamp": 1658480776, 110 | "creatorAccountId": "1e64ec02-5384-431b-9a34-c180e2e072f7", 111 | "latestEditorAccountId": "1e64ec02-5384-431b-9a34-c180e2e072f7", 112 | "id": 302134, 113 | "clubId": 19489, 114 | "clubName": "$s$900Flink's $fffclub", 115 | "name": "Icy Summer 2022", 116 | "mapsCount": 25, 117 | "mediaUrl": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/809d31a8-102d-4e27-9152-adece083e2d1/dds/game.dds?timestamp=1705423431.dds", 118 | "mediaUrlPngLarge": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/809d31a8-102d-4e27-9152-adece083e2d1/png/large.png?timestamp=1705423431.png", 119 | "mediaUrlPngMedium": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/809d31a8-102d-4e27-9152-adece083e2d1/png/medium.png?timestamp=1705423431.png", 120 | "mediaUrlPngSmall": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/809d31a8-102d-4e27-9152-adece083e2d1/png/small.png?timestamp=1705423431.png", 121 | "mediaUrlDds": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/809d31a8-102d-4e27-9152-adece083e2d1/dds/game.dds?timestamp=1705423431.dds", 122 | "mediaTheme": "" 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /docs/live/clubs/competitions.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club competitions 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/competition?length={length}&offset={offset}&name={name} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of competitions to retrieve 15 | required: true 16 | maximum: 250 17 | - name: offset 18 | type: integer 19 | description: The number of competitions to skip 20 | required: true 21 | - name: name 22 | type: string 23 | description: A string to search for in the competition names 24 | required: false 25 | --- 26 | 27 | Gets a list of club competitions. 28 | 29 | --- 30 | 31 | **Remarks**: 32 | 33 | - This endpoint does not return all available club competitions. When excluding the `name` parameter, it returns all verified clubs' competitions - otherwise the response is limited to 200 competitions. 34 | 35 | --- 36 | 37 | **Example request**: 38 | 39 | ```plain 40 | GET https://live-services.trackmania.nadeo.live/api/token/club/competition?length=3&offset=0 41 | ``` 42 | 43 | **Example response**: 44 | 45 | ```json 46 | { 47 | "clubCompetitionList": [ 48 | { 49 | "competitionId": 11125, 50 | "mediaUrl": "", 51 | "mediaTheme": "", 52 | "popularityLevel": 3, 53 | "popularityValue": 101231, 54 | "id": 486751, 55 | "clubId": 66661, 56 | "clubName": "Ubisoft Club", 57 | "name": "LASERHAWK", 58 | "creationTimestamp": 1698225982, 59 | "creatorAccountId": "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 60 | "latestEditorAccountId": "7ad33388-641e-4497-b063-c88e75552645" 61 | }, 62 | { 63 | "competitionId": 7184, 64 | "mediaUrl": "", 65 | "mediaTheme": "", 66 | "popularityLevel": 3, 67 | "popularityValue": 101231, 68 | "id": 421113, 69 | "clubId": 66661, 70 | "clubName": "Ubisoft Club", 71 | "name": "Mirage", 72 | "creationTimestamp": 1687429155, 73 | "creatorAccountId": "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 74 | "latestEditorAccountId": "50e65436-8ad7-40fb-9e02-ed09f267e55f" 75 | }, 76 | { 77 | "competitionId": 5636, 78 | "mediaUrl": "", 79 | "mediaTheme": "", 80 | "popularityLevel": 3, 81 | "popularityValue": 90732, 82 | "id": 380198, 83 | "clubId": 54094, 84 | "clubName": "CUPRA", 85 | "name": "Cupra cup 2", 86 | "creationTimestamp": 1682528914, 87 | "creatorAccountId": "6ce163d5-f240-4741-870b-f2adad843865", 88 | "latestEditorAccountId": "6ce163d5-f240-4741-870b-f2adad843865" 89 | } 90 | ], 91 | "maxPage": 10, 92 | "itemCount": 28 93 | } 94 | ``` 95 | -------------------------------------------------------------------------------- /docs/live/clubs/map-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club map review rooms 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/map-review?length={length}&offset={offset}&name={name} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of rooms to retrieve 15 | required: true 16 | maximum: 250 17 | - name: offset 18 | type: integer 19 | description: The number of rooms to skip 20 | required: true 21 | - name: name 22 | type: string 23 | description: A string to search for in the room names 24 | required: false 25 | --- 26 | 27 | Gets a list of club map review rooms. 28 | 29 | --- 30 | 31 | **Remarks**: 32 | 33 | - As of 2024-01-17, this endpoint's response links to `.dds` media files by default, while several scaled `.png` versions are available using separate fields (see example below for reference). 34 | 35 | --- 36 | 37 | **Example request**: 38 | 39 | ```plain 40 | GET https://live-services.trackmania.nadeo.live/api/token/club/map-review?length=3&offset=0 41 | ``` 42 | 43 | **Example response**: 44 | 45 | ```json 46 | { 47 | "clubMapReviewList": [ 48 | { 49 | "activityId": 506865, 50 | "mapReviewUid": "club_29917_506865", 51 | "timeLimit": 1200, 52 | "scalable": true, 53 | "allowVoteSkipMap": true, 54 | "submissionLimitation": true, 55 | "maxPlayer": 42, 56 | "public": true, 57 | "popularityLevel": 0, 58 | "submittedMapCount": 1, 59 | "id": 506865, 60 | "clubId": 29917, 61 | "clubName": "The Ritual", 62 | "name": "Review", 63 | "creationTimestamp": 1702550618, 64 | "creatorAccountId": "83596861-6441-4c3a-9cf2-37eec6c21440", 65 | "latestEditorAccountId": "83596861-6441-4c3a-9cf2-37eec6c21440", 66 | "game2webUrl": "https://www.trackmania.com/clubs29917/map-review/506865", 67 | "mediaUrl": "", 68 | "mediaUrlPngLarge": "", 69 | "mediaUrlPngMedium": "", 70 | "mediaUrlPngSmall": "", 71 | "mediaUrlDds": "", 72 | "mediaTheme": "" 73 | }, 74 | { 75 | "activityId": 480607, 76 | "mapReviewUid": "club_58353_480607", 77 | "timeLimit": 420, 78 | "scalable": true, 79 | "allowVoteSkipMap": false, 80 | "submissionLimitation": false, 81 | "maxPlayer": 64, 82 | "public": true, 83 | "popularityLevel": 0, 84 | "submittedMapCount": 3, 85 | "id": 480607, 86 | "clubId": 58353, 87 | "clubName": "$S$F6FDD0LLA$FFF MAPS", 88 | "name": "!", 89 | "creationTimestamp": 1697106965, 90 | "creatorAccountId": "8ffe695a-8aff-4378-a85f-a503a1abb256", 91 | "latestEditorAccountId": "8ffe695a-8aff-4378-a85f-a503a1abb256", 92 | "game2webUrl": "https://www.trackmania.com/clubs58353/map-review/480607", 93 | "mediaUrl": "", 94 | "mediaUrlPngLarge": "", 95 | "mediaUrlPngMedium": "", 96 | "mediaUrlPngSmall": "", 97 | "mediaUrlDds": "", 98 | "mediaTheme": "" 99 | }, 100 | { 101 | "activityId": 421171, 102 | "mapReviewUid": "club_66661_421171", 103 | "timeLimit": 180, 104 | "scalable": true, 105 | "allowVoteSkipMap": false, 106 | "submissionLimitation": false, 107 | "maxPlayer": 64, 108 | "public": true, 109 | "popularityLevel": 0, 110 | "submittedMapCount": 29, 111 | "id": 421171, 112 | "clubId": 66661, 113 | "clubName": "Ubisoft Club", 114 | "name": "Mirage", 115 | "creationTimestamp": 1687436865, 116 | "creatorAccountId": "7ad33388-641e-4497-b063-c88e75552645", 117 | "latestEditorAccountId": "7ad33388-641e-4497-b063-c88e75552645", 118 | "game2webUrl": "https://www.trackmania.com/clubs66661/map-review/421171", 119 | "mediaUrl": "", 120 | "mediaUrlPngLarge": "", 121 | "mediaUrlPngMedium": "", 122 | "mediaUrlPngSmall": "", 123 | "mediaUrlDds": "", 124 | "mediaTheme": "" 125 | } 126 | ], 127 | "maxPage": 4, 128 | "itemCount": 12 129 | } 130 | ``` 131 | -------------------------------------------------------------------------------- /docs/live/clubs/member-by-name.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get a club member by name 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/{clubId}/member/{memberName}/from-login 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: clubId 13 | type: string 14 | description: The club's ID 15 | required: true 16 | - name: memberName 17 | type: string 18 | description: The member's display name 19 | required: true 20 | --- 21 | 22 | Gets a specific player's information in the context of a club using the player's name. 23 | 24 | --- 25 | 26 | **Example request**: 27 | ```plain 28 | GET https://live-services.trackmania.nadeo.live/api/token/club/9/member/tooInfinite/from-login 29 | ``` 30 | 31 | **Example response**: 32 | ```json 33 | { 34 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 35 | "clubId": 9, 36 | "role": "Member", 37 | "creationTimestamp": 1614879432, 38 | "vip": false, 39 | "moderator": false, 40 | "hasFeatured": false, 41 | "pin": false, 42 | "useTag": false 43 | } 44 | ``` 45 | 46 | If the club does not exist or the player is not a member of the club, the response will contain an empty role and the current timestamp: 47 | 48 | ```json 49 | { 50 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 51 | "clubId": 1, 52 | "role": "", 53 | "creationTimestamp": 1661449122, 54 | "vip": false, 55 | "moderator": false, 56 | "hasFeatured": false, 57 | "pin": false, 58 | "useTag": false 59 | } 60 | ``` 61 | 62 | If the player name can't be resolved to an account, the response will contain an error: 63 | 64 | ```json 65 | [ 66 | "player:error-notFound" 67 | ] 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/live/clubs/member.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get a club member 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/{clubId}/member/{memberId} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: clubId 13 | type: string 14 | description: The club's ID 15 | required: true 16 | - name: memberId 17 | type: string 18 | description: The member's account ID 19 | required: true 20 | --- 21 | 22 | Gets a specific player's information in the context of a club using the player's account ID. 23 | 24 | --- 25 | 26 | **Example request**: 27 | ```plain 28 | GET https://live-services.trackmania.nadeo.live/api/token/club/9/member/7398eeb6-9b4e-44b8-a7a1-a2149955ac70 29 | ``` 30 | 31 | **Example response**: 32 | ```json 33 | { 34 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 35 | "clubId": 9, 36 | "role": "Creator", 37 | "creationTimestamp": 1591385606, 38 | "vip": true, 39 | "moderator": false, 40 | "hasFeatured": false, 41 | "pin": false, 42 | "useTag": false 43 | } 44 | ``` 45 | 46 | If the club does not exist, the player does not exist, or the player is not a member of the club, the response will contain an empty role and the current timestamp: 47 | 48 | ```json 49 | { 50 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 51 | "clubId": 1, 52 | "role": "", 53 | "creationTimestamp": 1661449122, 54 | "vip": false, 55 | "moderator": false, 56 | "hasFeatured": false, 57 | "pin": false, 58 | "useTag": false 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/live/clubs/members.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club members 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/{clubId}/member?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: clubId 13 | type: string 14 | description: The club's ID 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of members to retrieve 20 | required: true 21 | maximum: 250 22 | - name: offset 23 | type: integer 24 | description: The number of members to skip 25 | required: true 26 | --- 27 | 28 | Gets a list of members for a club. 29 | 30 | --- 31 | 32 | **Example request**: 33 | 34 | ```plain 35 | GET https://live-services.trackmania.nadeo.live/api/token/club/9/member?length=3&offset=0 36 | ``` 37 | 38 | **Example response**: 39 | 40 | ```json 41 | { 42 | "clubMemberList": [ 43 | { 44 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 45 | "clubId": 9, 46 | "role": "Creator", 47 | "creationTimestamp": 1591385606, 48 | "vip": true, 49 | "moderator": false, 50 | "hasFeatured": false, 51 | "pin": false, 52 | "useTag": false 53 | }, 54 | { 55 | "accountId": "a13831d2-5386-467b-bc65-264694dcaa4d", 56 | "clubId": 9, 57 | "role": "Member", 58 | "creationTimestamp": 1660938863, 59 | "vip": false, 60 | "moderator": false, 61 | "hasFeatured": false, 62 | "pin": false, 63 | "useTag": false 64 | }, 65 | { 66 | "accountId": "b73665ce-d3b4-4cb4-ac45-8f9a57ddaa1e", 67 | "clubId": 9, 68 | "role": "Member", 69 | "creationTimestamp": 1591439123, 70 | "vip": false, 71 | "moderator": false, 72 | "hasFeatured": false, 73 | "pin": false, 74 | "useTag": false 75 | } 76 | ], 77 | "maxPage": 152, 78 | "itemCount": 455 79 | } 80 | ``` 81 | 82 | If the club does not exist, the response will contain an empty list of members: 83 | 84 | ```json 85 | { 86 | "clubMemberList": [], 87 | "maxPage": 0, 88 | "itemCount": 0 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /docs/live/clubs/player.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get your club player info 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/player/info 7 | 8 | audience: NadeoLiveServices 9 | --- 10 | 11 | Gets club-related information for your account. 12 | 13 | --- 14 | 15 | **Remarks**: 16 | 17 | - This endpoint is only useful with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). 18 | 19 | --- 20 | 21 | **Example request**: 22 | 23 | ```plain 24 | GET https://live-services.trackmania.nadeo.live/api/token/club/player/info 25 | ``` 26 | 27 | **Example response**: 28 | 29 | ```json 30 | { 31 | "hasClubVip": true, 32 | "hasPlayerVip": true, 33 | "hasFollower": true, 34 | "tagClubId": 12730, 35 | "tag": "$F05TSH", 36 | "pinnedClub": 12730 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/live/clubs/room-by-id.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club room by ID 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/{clubID}/room/{roomID} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: clubID 13 | type: integer 14 | description: The ID of the club the room belongs to 15 | required: true 16 | - name: roomID 17 | type: integer 18 | description: The ID of the room to be requested 19 | required: true 20 | --- 21 | 22 | Gets the details of a specific club room. 23 | 24 | --- 25 | 26 | **Remarks**: 27 | 28 | - Club rooms connected to a dedicated server will have less information available - specifically, `maps` and `scriptSettings` will likely be empty. 29 | - As of 2024-01-17, this endpoint's response links to `.dds` media files by default, while several scaled `.png` versions are available using separate fields (see example below for reference). 30 | 31 | --- 32 | 33 | **Example request**: 34 | 35 | ```plain 36 | GET https://live-services.trackmania.nadeo.live/api/token/club/25/room/381929 37 | ``` 38 | 39 | **Example response**: 40 | 41 | ```json 42 | { 43 | "id": 381929, 44 | "clubId": 25, 45 | "clubName": "$s$fffTM $6F9Exchange", 46 | "nadeo": true, 47 | "roomId": 137873, 48 | "campaignId": null, 49 | "playerServerLogin": null, 50 | "activityId": 381929, 51 | "name": "TM Exchange Pack 1", 52 | "room": { 53 | "id": 137873, 54 | "name": "TM Exchange Pack 1", 55 | "region": "eu-west", 56 | "serverAccountId": "", 57 | "maxPlayers": 64, 58 | "playerCount": 0, 59 | "maps": [ 60 | "gXTE8jV8fF75hyXuRR8yuuhg6ym", 61 | "7AHlBi2o62SmM3D0lNCieqT6Er6", 62 | "tY8ydiSluqxKMw6bEkAG1V3oUde", 63 | ... 64 | "TB7r1bdx3xjIN89JwgKHjMusJJ6", 65 | "jC9YYcCbHpEuyIHDsCjIXuxWHdh", 66 | "Y_HCdBUZJ4vw96dPq1rDFRrKHSk" 67 | ], 68 | "script": "TrackMania/TM_TimeAttack_Online.Script.txt", 69 | "scalable": true, 70 | "scriptSettings": { 71 | "S_TimeLimit": { 72 | "key": "S_TimeLimit", 73 | "value": "360", 74 | "type": "integer" 75 | }, 76 | "S_DecoImageUrl_WhoAmIUrl": { 77 | "key": "S_DecoImageUrl_WhoAmIUrl", 78 | "value": "/api/club/25", 79 | "type": "text" 80 | }, 81 | "S_EnableJoinLeaveNotifications": { 82 | "key": "S_EnableJoinLeaveNotifications", 83 | "value": "false", 84 | "type": "boolean" 85 | }, 86 | "S_ForceLapsNb": { 87 | "key": "S_ForceLapsNb", 88 | "value": "-1", 89 | "type": "integer" 90 | } 91 | }, 92 | "serverInfo": null 93 | }, 94 | "popularityLevel": 0, 95 | "creationTimestamp": 1683021002, 96 | "creatorAccountId": "a07f01cd-afb0-4230-9c13-868c1ede28a3", 97 | "latestEditorAccountId": "a07f01cd-afb0-4230-9c13-868c1ede28a3", 98 | "password": false, 99 | "mediaUrl": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/6e29ffb6-ff4d-4e50-b9dd-e3c519864435/dds/game.dds?timestamp=1705430827.dds", 100 | "mediaUrlPngLarge": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/6e29ffb6-ff4d-4e50-b9dd-e3c519864435/png/large.png?timestamp=1705430827.png", 101 | "mediaUrlPngMedium": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/6e29ffb6-ff4d-4e50-b9dd-e3c519864435/png/medium.png?timestamp=1705430827.png", 102 | "mediaUrlPngSmall": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/6e29ffb6-ff4d-4e50-b9dd-e3c519864435/png/small.png?timestamp=1705430827.png", 103 | "mediaUrlDds": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/6e29ffb6-ff4d-4e50-b9dd-e3c519864435/dds/game.dds?timestamp=1705430827.dds", 104 | "mediaTheme": "" 105 | } 106 | ``` 107 | -------------------------------------------------------------------------------- /docs/live/clubs/upload-by-id.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club upload activity by ID 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/club/{clubID}/bucket/{bucketID}?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: clubID 13 | type: integer 14 | description: The ID of the club the upload activity belongs to 15 | required: true 16 | - name: bucketID 17 | type: integer 18 | description: The ID of the upload activity to be requested 19 | required: true 20 | query: 21 | - name: length 22 | type: integer 23 | description: The number of items to retrieve 24 | required: false 25 | default: 10 26 | - name: offset 27 | type: integer 28 | description: The number of items to skip 29 | required: false 30 | default: 0 31 | --- 32 | 33 | Gets the maps, items, or skins in a specific upload activity. 34 | 35 | --- 36 | 37 | **Remarks**: 38 | 39 | - The returned bucket will have one of three types : `map-upload`, `skin-upload`, or `item-upload`. These relate to club track uploads, skin uploads and item collection activities, respectively. 40 | - The primary identifier for items in the returned bucket is their `itemId`. For maps this will be a `mapUid` and for skins this is a `skinID`. 41 | - As of 2024-01-17, this endpoint's response links to `.dds` media files by default, while several scaled `.png`/`.jpg` versions are available using separate fields (see example below for reference). 42 | 43 | --- 44 | 45 | **Example request**: 46 | 47 | ```plain 48 | GET https://live-services.trackmania.nadeo.live/api/token/club/42175/bucket/344426 49 | ``` 50 | 51 | **Example response**: 52 | 53 | ```json 54 | { 55 | "type": "map-upload", 56 | "bucketItemList": [ 57 | { 58 | "itemId": "zOAI0h0WgikjTVv2RHcPShABLq0", 59 | "position": 0, 60 | "description": "", 61 | "mediaUrls": [], 62 | "mediaUrlsJpgLarge": [], 63 | "mediaUrlsJpgMedium": [], 64 | "mediaUrlsJpgSmall": [], 65 | "mediaUrlsDds": [] 66 | }, 67 | ... 68 | { 69 | "itemId": "wQS2NQxwV_PVweJb1MoBwft2bs6", 70 | "position": 9, 71 | "description": "", 72 | "mediaUrls": [], 73 | "mediaUrlsJpgLarge": [], 74 | "mediaUrlsJpgMedium": [], 75 | "mediaUrlsJpgSmall": [], 76 | "mediaUrlsDds": [] 77 | } 78 | ], 79 | "bucketItemCount": 63, 80 | "popularityLevel": 0, 81 | "popularityValue": 0, 82 | "creationTimestamp": 1673276709, 83 | "creatorAccountId": "fc8467b8-b253-457f-b8bb-3bbd2bb5bfdd", 84 | "latestEditorAccountId": "fc8467b8-b253-457f-b8bb-3bbd2bb5bfdd", 85 | "id": 344426, 86 | "clubId": 42175, 87 | "clubName": "$Z$f72ArEyeses$fff' $888Club", 88 | "name": "Randomly Generated G", 89 | "mediaUrl": "", 90 | "mediaUrlPngLarge": "", 91 | "mediaUrlPngMedium": "", 92 | "mediaUrlPngSmall": "", 93 | "mediaUrlDds": "", 94 | "mediaTheme": "" 95 | } 96 | ``` 97 | -------------------------------------------------------------------------------- /docs/live/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Live API 3 | category: reference 4 | --- 5 | 6 | # Live API 7 | 8 | The Live API is what the game queries most. 9 | 10 | It covers a wide range of use cases including clubs, rooms, campaigns, leaderboards and some more general information about maps. 11 | -------------------------------------------------------------------------------- /docs/live/leaderboards/campaign-ranking.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get season/campaign ranking for player 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/leaderboard/group/{groupUid}?accountId={accountId} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: groupUid 13 | type: string 14 | description: The ID of the group/season 15 | required: true 16 | query: 17 | - name: accountId 18 | type: string 19 | description: A player's account ID 20 | required: true 21 | --- 22 | 23 | Gets the player's regional ranks for the given group/season/campaign. 24 | 25 | --- 26 | 27 | **Remarks**: 28 | 29 | - The `groupUid` `"Personal_Best"` cannot be used for this endpoint because it requires a group that refers to a campaign or season. 30 | - Unlike some other leaderboard-related endpoints that use a `groupUid` parameter, this one also supports groups/seasons that are already closed. 31 | 32 | --- 33 | 34 | **Example request**: 35 | 36 | ```plain 37 | GET https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/ee54d6c5-954c-49b9-bd82-b51f8175b3f7?accountId=5b4d42f4-c2de-407d-b367-cbff3fe817bc 38 | ``` 39 | 40 | **Example response**: 41 | 42 | ```json 43 | { 44 | "groupUid": "ee54d6c5-954c-49b9-bd82-b51f8175b3f7", 45 | "sp": "2809", 46 | "zones": [ 47 | { 48 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 49 | "zoneName": "World", 50 | "ranking": { 51 | "position": 200000, 52 | "length": 0 53 | } 54 | }, 55 | { 56 | "zoneId": "301e2106-7e13-11e8-8060-e284abfd2bc4", 57 | "zoneName": "Europe", 58 | "ranking": { 59 | "position": 90000, 60 | "length": 0 61 | } 62 | }, 63 | { 64 | "zoneId": "301ff622-7e13-11e8-8060-e284abfd2bc4", 65 | "zoneName": "Germany", 66 | "ranking": { 67 | "position": 20000, 68 | "length": 0 69 | } 70 | }, 71 | { 72 | "zoneId": "301ff6b7-7e13-11e8-8060-e284abfd2bc4", 73 | "zoneName": "Baden-Württemberg", 74 | "ranking": { 75 | "position": 2338, 76 | "length": 0 77 | } 78 | }, 79 | { 80 | "zoneId": "301ff90f-7e13-11e8-8060-e284abfd2bc4", 81 | "zoneName": "Stuttgart", 82 | "ranking": { 83 | "position": 1409, 84 | "length": 0 85 | } 86 | } 87 | ] 88 | } 89 | ``` 90 | 91 | If the `groupUid` or the `accountId` is invalid, the response will be an empty object: 92 | 93 | ```json 94 | {} 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/live/leaderboards/campaign-top.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get season/campaign leaderboard 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/leaderboard/group/{groupUid}/top?length={length}&onlyWorld={onlyWorld}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: groupUid 13 | type: string 14 | description: The ID of the group/season 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of records to retrieve 20 | required: false 21 | default: 5 22 | max: 100 23 | - name: onlyWorld 24 | type: boolean 25 | description: Whether to only retrieve records from the world leaderboard 26 | required: false 27 | - name: offset 28 | type: integer 29 | description: The number of records to skip 30 | required: false 31 | default: 0 32 | --- 33 | 34 | Gets the leaderboard for the given group/season/campaign. 35 | 36 | --- 37 | 38 | **Remarks**: 39 | 40 | - The `groupUid` `"Personal_Best"` cannot be used for this endpoint because it requires a group that refers to a campaign or season. 41 | - Unlike some other leaderboard-related endpoints that use a `groupUid` parameter, this one also supports groups/seasons that are already closed. 42 | 43 | --- 44 | 45 | **Example request**: 46 | 47 | ```plain 48 | GET https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/b44807b9-9284-4730-a184-281069f45b60/top?onlyWorld=true&offset=0&length=100 49 | ``` 50 | 51 | **Example response**: 52 | 53 | ```json 54 | { 55 | "groupUid": "b44807b9-9284-4730-a184-281069f45b60", 56 | "tops": [ 57 | { 58 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 59 | "zoneName": "World", 60 | "top": [ 61 | { 62 | "accountId": "f37147a8-36f3-4c58-9577-bf0faff3aafa", 63 | "zoneId": "301e556c-7e13-11e8-8060-e284abfd2bc4", 64 | "zoneName": "Tyrol", 65 | "position": 1, 66 | "sp": "254088" 67 | }, 68 | { 69 | "accountId": "36460791-6ebe-4aa1-8ba4-8f1eab6acc7a", 70 | "zoneId": "302240ae-7e13-11e8-8060-e284abfd2bc4", 71 | "zoneName": "Norte", 72 | "position": 2, 73 | "sp": "189560" 74 | }, 75 | { 76 | "accountId": "05477e79-25fd-48c2-84c7-e1621aa46517", 77 | "zoneId": "30202b1c-7e13-11e8-8060-e284abfd2bc4", 78 | "zoneName": "Dresden", 79 | "position": 3, 80 | "sp": "184999" 81 | }, 82 | ... 83 | { 84 | "accountId": "ba023a24-6fa2-4142-a299-4f85eb2e017f", 85 | "zoneId": "301f60f6-7e13-11e8-8060-e284abfd2bc4", 86 | "zoneName": "Finland", 87 | "position": 98, 88 | "sp": "44617" 89 | }, 90 | { 91 | "accountId": "172f7930-77e6-4b38-8d97-c461cca430f0", 92 | "zoneId": "3022b0ab-7e13-11e8-8060-e284abfd2bc4", 93 | "zoneName": "Arizona", 94 | "position": 99, 95 | "sp": "44495" 96 | }, 97 | { 98 | "accountId": "87e8a0b9-fe8f-42e0-a08d-8f39ed56541b", 99 | "zoneId": "30205761-7e13-11e8-8060-e284abfd2bc4", 100 | "zoneName": "Veszprém", 101 | "position": 100, 102 | "sp": "44443" 103 | } 104 | ] 105 | } 106 | ] 107 | } 108 | ``` 109 | 110 | If the `groupUid` is invalid, the response will be an empty object: 111 | 112 | ```json 113 | {} 114 | ``` 115 | -------------------------------------------------------------------------------- /docs/live/leaderboards/medals.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map medal records 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/leaderboard/group/{groupUid}/map/{mapUid}/medals 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: groupUid 13 | type: string 14 | description: The ID of the group/season 15 | required: true 16 | - name: mapUid 17 | type: string 18 | description: The UID of the map 19 | required: true 20 | --- 21 | 22 | Gets automatically selected medal records for a map based on its leaderboard (when available). 23 | 24 | --- 25 | 26 | **Remarks**: 27 | - The `groupUid` `"Personal_Best"` can be used to get the global leaderboard. 28 | - Unlike some other leaderboard-related endpoints that use a `groupUid` parameter, this one also supports groups/seasons that are already closed. 29 | - Because this endpoint relies on leaderboard records that are close to the medal times, it doesn't always return all (or any) ghosts. Especially maps with a low number of records on the leaderboard won't work well. 30 | - The endpoint only returns records for the gold, silver and bronze medals. 31 | 32 | --- 33 | 34 | **Example request**: 35 | ```plain 36 | GET https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/Personal_Best/map/q1kDVh5fq1OCKfyFjJ2QAnB9UW8/medals 37 | ``` 38 | 39 | **Example response**: 40 | ```json 41 | { 42 | "groupUid": "Personal_Best", 43 | "mapUid": "q1kDVh5fq1OCKfyFjJ2QAnB9UW8", 44 | "medals": [ 45 | { 46 | "medal": "Gold", 47 | "accountId": "75328b1f-a38e-4ac0-9233-09a98dffd8ca", 48 | "zoneId": "3022973a-7e13-11e8-8060-e284abfd2bc4", 49 | "zoneName": "Zürich", 50 | "score": 46690 51 | }, 52 | { 53 | "medal": "Silver", 54 | "accountId": "188a5a83-0a14-493b-8155-11986db487ad", 55 | "zoneId": "3022a07d-7e13-11e8-8060-e284abfd2bc4", 56 | "zoneName": "Ukraine", 57 | "score": 49210 58 | }, 59 | { 60 | "medal": "Bronze", 61 | "accountId": "fbfee29a-76e3-43d8-96d7-bc9b425cfe33", 62 | "zoneId": "3022e90b-7e13-11e8-8060-e284abfd2bc4", 63 | "zoneName": "Ohio", 64 | "score": 52980 65 | } 66 | ] 67 | } 68 | ``` 69 | 70 | If the `groupUid` is invalid, the response will be an empty object: 71 | 72 | ```json 73 | {} 74 | ``` 75 | 76 | If the map does not exist, the response will return an empty list of medals: 77 | 78 | ```json 79 | { 80 | "groupUid": "Personal_Best", 81 | "mapUid": "q1kDVh5fq1OCKfyFjJ2QAnB9UW8_fake", 82 | "medals": [ 83 | 84 | ] 85 | } 86 | ``` 87 | -------------------------------------------------------------------------------- /docs/live/leaderboards/position.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get record positions by their time 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: POST 6 | route: /api/token/leaderboard/group/map?scores[{mapUid}]={score} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: mapUid 13 | type: string 14 | description: The UID of the map 15 | required: true 16 | max: 50 map UIDs 17 | - name: score 18 | type: integer 19 | description: The score/time (in milliseconds) to get the position for 20 | required: true 21 | body: 22 | - name: groupUid 23 | type: string 24 | description: The ID of the group/season for a specific map 25 | required: true 26 | --- 27 | 28 | The request body is an array of maps, identified by their mapUids: 29 | 30 | ```json 31 | { 32 | "maps": [ 33 | { 34 | "mapUid": "{mapUid}", 35 | "groupUid": "{groupUid}" 36 | } 37 | ] 38 | } 39 | ``` 40 | 41 | --- 42 | 43 | Gets position data for one or more records by their score/time. 44 | 45 | --- 46 | 47 | **Remarks**: 48 | 49 | - The `groupUid` `"Personal_Best"` can be used to get the global leaderboard. 50 | - When using a different `groupUid`, make sure you're only referencing currently open leaderboards. Maps with closed leaderboards will not be included in the response. 51 | - The `mapUid` parameter in the URL has to correspond with a map in the request body. 52 | - This endpoint supports up to 50 maps at once - they need to be added to the request body's array as well as to the query parameters (see example below). 53 | - This endpoint can sometimes be very delayed - there's been cases where it has returned data that was outdated for multiple hours. On average, this route should be up to date within about three hours - some maps are prioritized though (official campaign maps and current TOTDs), so they are typically updated every five minutes. 54 | - If the authenticated account has a record on the requested map, no scores lower than that record can be requested - it's recommended to use this endpoint with an account that does not have any records. 55 | - The positions returned by this endpoint don't correspond to existing records, instead they tell you what a new record's position would be given the requested score. 56 | 57 | --- 58 | 59 | **Example request**: 60 | 61 | ```plain 62 | POST https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/map?scores[gjt2DWATrQ_NdrbrXG0G9oDpTfh]=15800&scores[XiGZvMOqIgT3_g0TdeFa0lxMp46]=17500 63 | ``` 64 | 65 | ```json 66 | { 67 | "maps": [ 68 | { 69 | "mapUid": "gjt2DWATrQ_NdrbrXG0G9oDpTfh", 70 | "groupUid": "Personal_Best" 71 | }, 72 | { 73 | "mapUid": "XiGZvMOqIgT3_g0TdeFa0lxMp46", 74 | "groupUid": "Personal_Best" 75 | } 76 | ] 77 | } 78 | ``` 79 | 80 | **Example response**: 81 | 82 | ```json 83 | [ 84 | { 85 | "groupUid": "Personal_Best", 86 | "mapUid": "gjt2DWATrQ_NdrbrXG0G9oDpTfh", 87 | "score": 15800, 88 | "zones": [ 89 | { 90 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 91 | "zoneName": "World", 92 | "ranking": { 93 | "position": 294, 94 | "length": 0 95 | } 96 | } 97 | ] 98 | }, 99 | { 100 | "groupUid": "Personal_Best", 101 | "mapUid": "XiGZvMOqIgT3_g0TdeFa0lxMp46", 102 | "score": 17500, 103 | "zones": [ 104 | { 105 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 106 | "zoneName": "World", 107 | "ranking": { 108 | "position": 42, 109 | "length": 0 110 | } 111 | } 112 | ] 113 | } 114 | ] 115 | ``` 116 | 117 | If a `groupUid` or a `mapUid` is invalid (or the referenced leaderboard is closed), the response will simply omit that map's record. 118 | 119 | If the query parameters reference a map that is not contained in the request body, the endpoint may return a `500` error. 120 | -------------------------------------------------------------------------------- /docs/live/leaderboards/top-club.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map leaderboards for club members 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/leaderboard/group/{groupUid}/map/{mapUid}/club/{clubId}/top?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: groupUid 13 | type: string 14 | description: The ID of the group/season 15 | required: true 16 | - name: mapUid 17 | type: string 18 | description: The UID of the map 19 | required: true 20 | - name: clubId 21 | type: string 22 | description: The ID of the club 23 | required: true 24 | query: 25 | - name: length 26 | type: integer 27 | description: The number of records to retrieve 28 | required: false 29 | default: 5 30 | max: 100 31 | - name: offset 32 | type: integer 33 | description: The number of records to skip 34 | required: false 35 | default: 0 36 | --- 37 | 38 | Gets records from a map's leaderboard for members of a club. 39 | 40 | --- 41 | 42 | **Remarks**: 43 | 44 | - The `groupUid` `"Personal_Best"` can be used to get the global leaderboard. 45 | - This endpoint only allows you to read a leaderboard's first 10,000 records. The rest of the leaderboard is not available at this level of detail. 46 | - If a `length` higher than `100` is requested, the API will successfully return only the first 100 records. 47 | - If the map author has set a secret threshold score for their map, this endpoint will not return any actual `score` values for some entries. Instead, those leaderboard entries will contain `-1` in the `score` field. 48 | 49 | --- 50 | 51 | **Example request**: 52 | 53 | ```plain 54 | GET https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/Personal_Best/map/k4TKkf1JSlWTEEZdCc9UCNTokk6/club/9/top?offset=0&length=100 55 | ``` 56 | 57 | **Example response**: 58 | 59 | ```json 60 | { 61 | "groupUid": "Personal_Best", 62 | "mapUid": "k4TKkf1JSlWTEEZdCc9UCNTokk6", 63 | "clubId": 9, 64 | "length": 310, 65 | "top": [ 66 | { 67 | "accountId": "febdee2f-744e-4a56-9126-ca3b1b034ea0", 68 | "zoneId": "3022ed9f-7e13-11e8-8060-e284abfd2bc4", 69 | "zoneName": "Texas", 70 | "position": 1, 71 | "score": 26464 72 | }, 73 | ... 74 | { 75 | "accountId": "23bc4ff4-01e9-42ab-b685-8d06ca139855", 76 | "zoneId": "30226ac4-7e13-11e8-8060-e284abfd2bc4", 77 | "zoneName": "Catalunya", 78 | "position": 100, 79 | "score": 27795 80 | } 81 | ] 82 | } 83 | ``` 84 | 85 | If the `groupUid` is invalid, the response will be an empty object: 86 | 87 | ```json 88 | {} 89 | ``` 90 | 91 | If the map does not exist, the response will show an empty leaderboard: 92 | 93 | ```json 94 | { 95 | "groupUid": "Personal_Best", 96 | "mapUid": "k4TKkf1JSlWTEEZdCc9UCNTokk6_fake", 97 | "clubId": 9, 98 | "length": 0, 99 | "top": [] 100 | } 101 | ``` 102 | -------------------------------------------------------------------------------- /docs/live/leaderboards/top.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map leaderboards 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/leaderboard/group/{groupUid}/map/{mapUid}/top?length={length}&onlyWorld={onlyWorld}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: groupUid 13 | type: string 14 | description: The ID of the group/season 15 | required: true 16 | - name: mapUid 17 | type: string 18 | description: The UID of the map 19 | required: true 20 | query: 21 | - name: length 22 | type: integer 23 | description: The number of records to retrieve 24 | required: false 25 | default: 5 26 | max: 100 27 | - name: onlyWorld 28 | type: boolean 29 | description: Whether to only retrieve records from the world leaderboard 30 | required: false 31 | - name: offset 32 | type: integer 33 | description: The number of records to skip 34 | required: false 35 | default: 0 36 | --- 37 | 38 | Gets records from a map's leaderboard. 39 | 40 | --- 41 | 42 | **Remarks**: 43 | 44 | - The `groupUid` `"Personal_Best"` can be used to get the global leaderboard. 45 | - `onlyWorld=true` is required to retrieve more than the first five records. Without it, `length` and `offset` will have no effect. 46 | - This endpoint only allows you to read a leaderboard's first 10,000 records. The rest of the leaderboard is not available at this level of detail. 47 | - If a `length` higher than `100` is requested, the API will successfully return only the first 100 records. 48 | - As of December 11th 2024, this endpoint's response also contains a `timestamp` for each leaderboard entry, which corresponds to the time the relevant record was set. 49 | - If the map author has set a secret threshold score for their map, this endpoint will not return any actual `score` values for some entries. Instead, those leaderboard entries will contain `-1` in the `score` field. 50 | 51 | --- 52 | 53 | **Example request**: 54 | 55 | ```plain 56 | GET https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/Personal_Best/map/ZJw6_4CItmVlRMPgELl4Q37Utw2/top?onlyWorld=true&length=10&offset=50 57 | ``` 58 | 59 | **Example response**: 60 | 61 | ```json 62 | { 63 | "groupUid": "Personal_Best", 64 | "mapUid": "ZJw6_4CItmVlRMPgELl4Q37Utw2", 65 | "tops": [ 66 | { 67 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 68 | "zoneName": "World", 69 | "top": [ 70 | { 71 | "accountId": "6ec3711d-a722-4bc3-b952-96e80410b7ff", 72 | "zoneId": "301fbe37-7e13-11e8-8060-e284abfd2bc4", 73 | "zoneName": "Corrèze", 74 | "position": 51, 75 | "score": 53145, 76 | "timestamp": 1658783398 77 | }, 78 | ... 79 | { 80 | "accountId": "aa4e375f-d23e-4915-8d53-8b3307e06764", 81 | "zoneId": "301ffccb-7e13-11e8-8060-e284abfd2bc4", 82 | "zoneName": "Nürnberg", 83 | "position": 60, 84 | "score": 53158, 85 | "timestamp": 1658772554 86 | } 87 | ] 88 | } 89 | ] 90 | } 91 | ``` 92 | 93 | If the `groupUid` is invalid, the response will be an empty object: 94 | 95 | ```json 96 | {} 97 | ``` 98 | 99 | If the map does not exist, the response will show an empty leaderboard: 100 | 101 | ```json 102 | { 103 | "groupUid": "Personal_Best", 104 | "mapUid": "ZJw6_4CItmVlRMPgELl4Q37Utw2_fake", 105 | "tops": [ 106 | { 107 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 108 | "zoneName": "World", 109 | "top": [] 110 | } 111 | ] 112 | } 113 | ``` 114 | -------------------------------------------------------------------------------- /docs/live/leaderboards/trophies.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player trophy rankings 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: POST 6 | route: /api/token/leaderboard/trophy/player 7 | 8 | audience: NadeoLiveServices 9 | 10 | --- 11 | 12 | The request body is an array of players, identified by their account IDs: 13 | ```json 14 | { 15 | "listPlayer": [ 16 | { 17 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc" 18 | }, 19 | { 20 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70" 21 | } 22 | ] 23 | } 24 | ``` 25 | 26 | --- 27 | 28 | Gets the specified players' trophy leaderboard positions for each of their zones. 29 | 30 | --- 31 | 32 | **Example request**: 33 | ```plain 34 | POST https://live-services.trackmania.nadeo.live/api/token/leaderboard/trophy/player 35 | ``` 36 | ```json 37 | { 38 | "listPlayer": [ 39 | { 40 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc" 41 | }, 42 | { 43 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70" 44 | } 45 | ] 46 | } 47 | ``` 48 | 49 | **Example response**: 50 | ```json 51 | { 52 | "rankings": [ 53 | { 54 | "countPoint": 1648346, 55 | "zones": [ 56 | { 57 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 58 | "zoneName": "World", 59 | "ranking": { 60 | "position": 20000, 61 | "length": 0 62 | } 63 | }, 64 | { 65 | "zoneId": "301e2106-7e13-11e8-8060-e284abfd2bc4", 66 | "zoneName": "Europe", 67 | "ranking": { 68 | "position": 9784, 69 | "length": 0 70 | } 71 | }, 72 | { 73 | "zoneId": "302094fd-7e13-11e8-8060-e284abfd2bc4", 74 | "zoneName": "Netherlands", 75 | "ranking": { 76 | "position": 500, 77 | "length": 0 78 | } 79 | }, 80 | { 81 | "zoneId": "30209bf3-7e13-11e8-8060-e284abfd2bc4", 82 | "zoneName": "Noord-Holland", 83 | "ranking": { 84 | "position": 62, 85 | "length": 0 86 | } 87 | } 88 | ], 89 | "accountId": "7398eeb6-9b4e-44b8-a7a1-a2149955ac70", 90 | "echelon": 5 91 | }, 92 | { 93 | "countPoint": 2080947, 94 | "zones": [ 95 | { 96 | "zoneId": "301e1b69-7e13-11e8-8060-e284abfd2bc4", 97 | "zoneName": "World", 98 | "ranking": { 99 | "position": 8980, 100 | "length": 0 101 | } 102 | }, 103 | { 104 | "zoneId": "301e2106-7e13-11e8-8060-e284abfd2bc4", 105 | "zoneName": "Europe", 106 | "ranking": { 107 | "position": 7405, 108 | "length": 0 109 | } 110 | }, 111 | { 112 | "zoneId": "301ff622-7e13-11e8-8060-e284abfd2bc4", 113 | "zoneName": "Germany", 114 | "ranking": { 115 | "position": 1818, 116 | "length": 0 117 | } 118 | }, 119 | { 120 | "zoneId": "301ff6b7-7e13-11e8-8060-e284abfd2bc4", 121 | "zoneName": "Baden-Württemberg", 122 | "ranking": { 123 | "position": 294, 124 | "length": 0 125 | } 126 | }, 127 | { 128 | "zoneId": "301ff90f-7e13-11e8-8060-e284abfd2bc4", 129 | "zoneName": "Stuttgart", 130 | "ranking": { 131 | "position": 163, 132 | "length": 0 133 | } 134 | } 135 | ], 136 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 137 | "echelon": 5 138 | } 139 | ], 140 | "length": 0 141 | } 142 | ``` 143 | 144 | If an `accountId` is invalid, it will be ignored in the response. 145 | -------------------------------------------------------------------------------- /docs/live/maniapubs/active.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get active Maniapubs 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/advertising/display/active 7 | 8 | audience: NadeoLiveServices 9 | --- 10 | 11 | Get a list of active Maniapubs (in-game ads) along with their metadata. 12 | 13 | --- 14 | 15 | **Remarks**: 16 | 17 | - This endpoint doesn't return zone-specific Maniapubs - it might depend on the account's current zone, but you can't request Maniapubs by zone directly. 18 | - As of 2023-12-21, this endpoint's response links to `.dds` media files by default, while several scaled `.jpg` versions are available using separate fields (see example below for reference). 19 | 20 | --- 21 | 22 | **Example request**: 23 | 24 | ```plain 25 | GET https://live-services.trackmania.nadeo.live/api/token/advertising/display/active 26 | ``` 27 | 28 | **Example response**: 29 | 30 | ```json 31 | { 32 | "displayList": [ 33 | { 34 | "campaignUid": "b7ef5b35-f1bf-41ae-a58e-7356c86b9c2d", 35 | "name": "Beacon World League", 36 | "adType": "ugc", 37 | "externalUrl": "https://discord.gg/aJBcSYN2dj", 38 | "screen2x3Url": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/3e5306aa-8e44-4cbe-bb26-aeee38a2a70f/dds/game.dds?timestamp=1702643396.dds", 39 | "screen2x3UrlJpgLarge": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/3e5306aa-8e44-4cbe-bb26-aeee38a2a70f/jpg/large.jpg?timestamp=1702643396.jpg", 40 | "screen2x3UrlJpgMedium": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/3e5306aa-8e44-4cbe-bb26-aeee38a2a70f/jpg/medium.jpg?timestamp=1702643396.jpg", 41 | "screen2x3UrlJpgSmall": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/3e5306aa-8e44-4cbe-bb26-aeee38a2a70f/jpg/small.jpg?timestamp=1702643396.jpg", 42 | "screen2x3UrlDds": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/3e5306aa-8e44-4cbe-bb26-aeee38a2a70f/dds/game.dds?timestamp=1702643396.dds", 43 | "screen16x9Url": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/dds/game.dds?timestamp=1702987488.dds", 44 | "screen16x9UrlJpgLarge": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/jpg/large.jpg?timestamp=1702987488.jpg", 45 | "screen16x9UrlJpgMedium": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/jpg/medium.jpg?timestamp=1702987488.jpg", 46 | "screen16x9UrlJpgSmall": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/jpg/small.jpg?timestamp=1702987488.jpg", 47 | "screen16x9UrlDds": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/dds/game.dds?timestamp=1702987488.dds", 48 | "screen64x41Url": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/dds/game.dds?timestamp=1702987488.dds", 49 | "screen64x41UrlJpgLarge": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/jpg/large.jpg?timestamp=1702987488.jpg", 50 | "screen64x41UrlJpgMedium": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/jpg/medium.jpg?timestamp=1702987488.jpg", 51 | "screen64x41UrlJpgSmall": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/jpg/small.jpg?timestamp=1702987488.jpg", 52 | "screen64x41UrlDds": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/335586ba-e30a-4f75-8e24-8a23deab5afa/dds/game.dds?timestamp=1702987488.dds", 53 | "screen64x10Url": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/9effcdf4-66ab-49af-af68-8f85068b3d53/dds/game.dds?timestamp=1702651418.dds", 54 | "screen64x10UrlJpgLarge": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/9effcdf4-66ab-49af-af68-8f85068b3d53/jpg/large.jpg?timestamp=1702651418.jpg", 55 | "screen64x10UrlJpgMedium": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/9effcdf4-66ab-49af-af68-8f85068b3d53/jpg/medium.jpg?timestamp=1702651418.jpg", 56 | "screen64x10UrlJpgSmall": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/9effcdf4-66ab-49af-af68-8f85068b3d53/jpg/small.jpg?timestamp=1702651418.jpg", 57 | "screen64x10UrlDds": "https://trackmania-prod-media-s3.cdn.ubi.com/media/image/live-api/9effcdf4-66ab-49af-af68-8f85068b3d53/dds/game.dds?timestamp=1702651418.dds", 58 | "mediaUrl": "", 59 | "displayFormat": "", 60 | "ratio": 0, 61 | "displayRatio": 0, 62 | "endTimestamp": 1703460488, 63 | "relativeEnd": 282414 64 | }, 65 | ... 66 | ], 67 | "itemCount": 10 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/live/maps/add-favorite.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Add favorite map 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: POST 6 | route: /api/token/map/favorite/{mapUid}/add 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: mapUid 13 | type: string 14 | description: The UID of the map 15 | required: true 16 | --- 17 | 18 | Adds a map to your authenticated account's favorites. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - This endpoint is only useful with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). 25 | 26 | --- 27 | 28 | **Example request**: 29 | 30 | ```plain 31 | POST https://live-services.trackmania.nadeo.live/api/token/map/favorite/EgUgXeBV8vpEth2hZgSzLhlHRs8/add 32 | ``` 33 | 34 | **Example response**: 35 | 36 | A successful response has no content and a `204` response code. 37 | 38 | Example response if the requested map does not exist: 39 | 40 | ```json 41 | ["map:error-notFound"] 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/live/maps/favorites.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get favorite maps 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/map/favorite?offset={offset}&length={length}&sort={sort}&order={order}&mapType={mapType}&playable={playable} 7 | 8 | audience: NadeoLiveServices 9 | parameters: 10 | query: 11 | - name: offset 12 | type: integer 13 | description: The number of maps to skip 14 | required: true 15 | - name: length 16 | type: integer 17 | description: The number of maps to retrieve 18 | required: true 19 | minimum: 1 20 | maximum: 100 21 | - name: sort 22 | type: string 23 | description: The sorting of the maps 24 | required: false 25 | default: "date" 26 | - name: order 27 | type: string 28 | description: The order of the maps based on the sorting 29 | required: false 30 | default: "desc" 31 | - name: mapType 32 | type: string 33 | description: The map type filter 34 | required: false 35 | - name: playable 36 | type: boolean 37 | description: Whether the map is validated and playable 38 | required: false 39 | --- 40 | 41 | Retrieves your authenticated account's favorite tracks along with their information. 42 | 43 | --- 44 | 45 | **Remarks**: 46 | 47 | - This endpoint is only useful with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). 48 | - When no `mapType` filter is applied, all available maps are returned regardless of their type. 49 | - Examples of supported map types to filter by are `"TrackMania\TM_Race"`, `"TrackMania\TM_Royal"` and `"TrackMania\TM_Stunt"`. 50 | 51 | --- 52 | 53 | **Example request**: 54 | 55 | ```plain 56 | GET https://live-services.trackmania.nadeo.live/api/token/map/favorite?offset=0&length=1&sort=date&order=desc&mapType=Trackmania\TM_Race&playable=true 57 | ``` 58 | 59 | **Example response**: 60 | 61 | ```json 62 | { 63 | "mapList": [ 64 | { 65 | "uid": "QleO8OiNAkIXrZs6r0YLSrLBjEi", 66 | "mapId": "606e4e16-f1d6-467c-9859-f1837a452166", 67 | "name": "MIDNIGHT METROPOLIS", 68 | "author": "144fce06-9b90-4af9-a5b0-9148bcc0566f", 69 | "submitter": "144fce06-9b90-4af9-a5b0-9148bcc0566f", 70 | "authorTime": 55910, 71 | "goldTime": 60000, 72 | "silverTime": 68000, 73 | "bronzeTime": 84000, 74 | "nbLaps": 0, 75 | "valid": false, 76 | "downloadUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/9c20aff3-2046-4d7c-aa9b-52617d8d99e2", 77 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/4889bf39-a4f3-40b2-a582-9fa926e41930.jpg", 78 | "uploadTimestamp": 1631578171, 79 | "updateTimestamp": 1658421115, 80 | "fileSize": null, 81 | "public": false, 82 | "favorite": false, 83 | "playable": true, 84 | "mapStyle": "TrackMania\\TM_Race", 85 | "mapType": "TrackMania\\TM_Race", 86 | "collectionName": "Stadium" 87 | } 88 | ], 89 | "itemCount": 1 90 | } 91 | ``` 92 | -------------------------------------------------------------------------------- /docs/live/maps/info-multiple.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map info (multiple) 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/map/get-multiple?mapUidList={mapUidList} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: mapUidList 13 | type: string 14 | description: A comma-separated list of map UIDs 15 | required: true 16 | max: 100 map UIDs 17 | --- 18 | 19 | Gets information about multiple maps via their UIDs. 20 | 21 | --- 22 | 23 | **Remarks**: 24 | 25 | - Invalid UIDs will be ignored in the result without any visible errors. 26 | - This endpoint only accepts `mapUid`s - to get map information for a `mapId` (or to translate `mapId`s to `mapUid`s), you can use the [Core API's map info (multiple) endpoint](/core/maps/info-multiple). 27 | 28 | --- 29 | 30 | **Example request**: 31 | 32 | ```plain 33 | GET https://live-services.trackmania.nadeo.live/api/token/map/get-multiple?mapUidList=YewzuEnjmnh_ShMW1cX0puuZHcf,HisPAAWhTMTjQPxhMJtMak7Daud 34 | ``` 35 | 36 | **Example response**: 37 | 38 | ```json 39 | { 40 | "mapList": [ 41 | { 42 | "uid": "YewzuEnjmnh_ShMW1cX0puuZHcf", 43 | "mapId": "17d72086-de9c-406b-8f8f-364e41d3e3bf", 44 | "name": "$009L$00Aa$00Bs$00Ct $063O$073u$072t$082p$081o$091s$090t$fff ft Agrabou", 45 | "author": "78332411-010f-4d61-84d8-0db1d6b5f8c0", 46 | "submitter": "5f9c2a43-593f-4e84-a64d-82319058dd3a", 47 | "authorTime": 45900, 48 | "goldTime": 49000, 49 | "silverTime": 56000, 50 | "bronzeTime": 69000, 51 | "nbLaps": 0, 52 | "valid": false, 53 | "downloadUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/b0e97432-eefe-40dc-96ef-583ec0c23099", 54 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/83a1ee79-9c41-4be2-9e30-67bd8a8bf4fe.jpg", 55 | "uploadTimestamp": 1658695534, 56 | "updateTimestamp": 1661191160, 57 | "fileSize": null, 58 | "public": false, 59 | "favorite": false, 60 | "playable": true, 61 | "mapStyle": "", 62 | "mapType": "TrackMania\\TM_Race", 63 | "collectionName": "Stadium" 64 | }, 65 | { 66 | "uid": "HisPAAWhTMTjQPxhMJtMak7Daud", 67 | "mapId": "0ee6d969-f58f-4a7e-8716-7d25a795dd03", 68 | "name": "$n$oWORK IN $FC3PROGRESS", 69 | "author": "912ae713-d291-44c7-b34e-bd96c655dc64", 70 | "submitter": "912ae713-d291-44c7-b34e-bd96c655dc64", 71 | "authorTime": 46368, 72 | "goldTime": 49000, 73 | "silverTime": 56000, 74 | "bronzeTime": 70000, 75 | "nbLaps": 0, 76 | "valid": false, 77 | "downloadUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/a41c5eb7-9632-4c14-af02-b1cc760a35e0", 78 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/c959a0dc-66be-4843-bf30-a3b70b52f722.jpg", 79 | "uploadTimestamp": 1659006890, 80 | "updateTimestamp": 1661109091, 81 | "fileSize": null, 82 | "public": false, 83 | "favorite": false, 84 | "playable": true, 85 | "mapStyle": "", 86 | "mapType": "TrackMania\\TM_Race", 87 | "collectionName": "Stadium" 88 | } 89 | ], 90 | "itemCount": 2 91 | } 92 | ``` 93 | 94 | If a `mapUid` is invalid, that map will not be returned in the response. 95 | -------------------------------------------------------------------------------- /docs/live/maps/info.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get map info 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/map/{mapUid} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: mapUid 13 | type: string 14 | description: The UID of the map 15 | required: true 16 | --- 17 | 18 | Gets information about a map via its UID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - This endpoint only accepts `mapUid`s - to get map information for a `mapId` (or to translate `mapId`s to `mapUid`s), you can use the [Core API's map info (multiple) endpoint](/core/maps/info-multiple). 25 | 26 | --- 27 | 28 | **Example request**: 29 | 30 | ```plain 31 | GET https://live-services.trackmania.nadeo.live/api/token/map/QleO8OiNAkIXrZs6r0YLSrLBjEi 32 | ``` 33 | 34 | **Example response**: 35 | 36 | ```json 37 | { 38 | "uid": "QleO8OiNAkIXrZs6r0YLSrLBjEi", 39 | "mapId": "606e4e16-f1d6-467c-9859-f1837a452166", 40 | "name": "MIDNIGHT METROPOLIS", 41 | "author": "144fce06-9b90-4af9-a5b0-9148bcc0566f", 42 | "submitter": "144fce06-9b90-4af9-a5b0-9148bcc0566f", 43 | "authorTime": 55910, 44 | "goldTime": 60000, 45 | "silverTime": 68000, 46 | "bronzeTime": 84000, 47 | "nbLaps": 0, 48 | "valid": false, 49 | "downloadUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/9c20aff3-2046-4d7c-aa9b-52617d8d99e2", 50 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/4889bf39-a4f3-40b2-a582-9fa926e41930.jpg", 51 | "uploadTimestamp": 1631578171, 52 | "updateTimestamp": 1658421115, 53 | "fileSize": null, 54 | "public": false, 55 | "favorite": false, 56 | "playable": true, 57 | "mapStyle": "TrackMania\\TM_Race", 58 | "mapType": "TrackMania\\TM_Race", 59 | "collectionName": "Stadium" 60 | } 61 | ``` 62 | 63 | Example response if the requested map does not exist: 64 | 65 | ```json 66 | ["map:error-notFound"] 67 | ``` 68 | 69 | Note: Be careful to check the response type; a valid track will return an object, but an invalid track will return an array with a string in it. 70 | -------------------------------------------------------------------------------- /docs/live/maps/remove-favorite.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Remove favorite map 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: POST 6 | route: /api/token/map/favorite/{mapUid}/remove 7 | 8 | audience: NadeoLiveServices 9 | parameters: 10 | path: 11 | - name: mapUid 12 | type: string 13 | description: The UID of the map 14 | required: true 15 | --- 16 | 17 | Removes a map from your authenticated account's favorites. 18 | 19 | --- 20 | 21 | **Remarks**: 22 | 23 | - This endpoint is only useful with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). 24 | 25 | --- 26 | 27 | **Example request**: 28 | 29 | ```plain 30 | POST https://live-services.trackmania.nadeo.live/api/token/map/favorite/EgUgXeBV8vpEth2hZgSzLhlHRs8/remove 31 | ``` 32 | 33 | **Example response**: 34 | 35 | A successful response has no content and a `204` response code. 36 | 37 | Example response if the requested map does not exist: 38 | 39 | ```json 40 | ["map:error-notFound"] 41 | ``` 42 | 43 | Example response if the requested map is not among your favorites: 44 | 45 | ```json 46 | ["mapFavorite:error-notFound"] 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/live/maps/uploaded.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get your uploaded maps 3 | 4 | url: https://live-services.trackmania.nadeo.live 5 | method: GET 6 | route: /api/token/map?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: offset 13 | type: integer 14 | description: The number of maps to skip 15 | required: false 16 | - name: length 17 | type: integer 18 | description: The number of maps to retrieve 19 | required: false 20 | --- 21 | 22 | Gets a list of your authenticated account's uploaded maps, sorted by upload date. 23 | 24 | --- 25 | 26 | **Remarks**: 27 | 28 | - This endpoint is only useful with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). 29 | 30 | --- 31 | 32 | **Example request**: 33 | 34 | ```plain 35 | GET https://live-services.trackmania.nadeo.live/api/token/map?length=1&offset=0 36 | ``` 37 | 38 | **Example response**: 39 | 40 | ```json 41 | { 42 | "mapList": [ 43 | { 44 | "uid": "QleO8OiNAkIXrZs6r0YLSrLBjEi", 45 | "mapId": "606e4e16-f1d6-467c-9859-f1837a452166", 46 | "name": "MIDNIGHT METROPOLIS", 47 | "author": "144fce06-9b90-4af9-a5b0-9148bcc0566f", 48 | "submitter": "144fce06-9b90-4af9-a5b0-9148bcc0566f", 49 | "authorTime": 55910, 50 | "goldTime": 60000, 51 | "silverTime": 68000, 52 | "bronzeTime": 84000, 53 | "nbLaps": 0, 54 | "valid": false, 55 | "downloadUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/9c20aff3-2046-4d7c-aa9b-52617d8d99e2", 56 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/4889bf39-a4f3-40b2-a582-9fa926e41930.jpg", 57 | "uploadTimestamp": 1631578171, 58 | "updateTimestamp": 1658421115, 59 | "fileSize": null, 60 | "public": false, 61 | "favorite": false, 62 | "playable": true, 63 | "mapStyle": "TrackMania\\TM_Race", 64 | "mapType": "TrackMania\\TM_Race", 65 | "collectionName": "Stadium" 66 | } 67 | ], 68 | "itemCount": 68 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/meet/challenges/challenge.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get challenge 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/challenges/{challengeId} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: challengeId 13 | type: string 14 | description: A valid challenge ID 15 | required: true 16 | --- 17 | 18 | Gets challenge details for a challenge ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - Note that challenges are different from competitions - challenges are separate leaderboard structures that can be part of a competition (for example in the form of a qualifying session). 25 | - Typically challenges are used for qualifiers in larger competitions - the relevant `challengeId` can be retrieved using the [competition rounds endpoint](/meet/competitions/rounds). 26 | 27 | --- 28 | 29 | **Example request**: 30 | 31 | ```plain 32 | GET https://meet.trackmania.nadeo.club/api/challenges/409 33 | ``` 34 | 35 | **Example response**: 36 | 37 | ```json 38 | { 39 | "id": 409, 40 | "uid": "8c4a18cc-dca7-4fe2-8dc3-55e40120ad26", 41 | "name": "Cup of the Day 2021-08-14 #2 - Challenge", 42 | "scoreDirection": "ASC", 43 | "startDate": 1628989260, 44 | "endDate": 1628990160, 45 | "status": "SERVER_DELETED", 46 | "resultsVisibility": "PUBLIC", 47 | "creator": "afe7e1c1-7086-48f7-bde9-a7e320647510", 48 | "admins": [ 49 | "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 50 | "54e4dda4-522d-496f-8a8b-fe0d0b5a2a8f", 51 | "2116b392-d808-4264-923f-2bfcfa60a570", 52 | "6ce163d5-f240-4741-870b-f2adad843865" 53 | ], 54 | "nbServers": 0, 55 | "autoScale": true, 56 | "nbMaps": 1, 57 | "leaderboardId": 2003, 58 | "deletedOn": null, 59 | "leaderboardType": "SUM", 60 | "completeTimeout": 5 61 | } 62 | ``` 63 | 64 | If a `challengeId` is invalid, the response will contain a `404` response code. 65 | -------------------------------------------------------------------------------- /docs/meet/challenges/challenges.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get challenges 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/challenges?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of challenges to retrieve 15 | required: false 16 | default: 10 17 | max: 100 18 | - name: offset 19 | type: integer 20 | description: The number of challenges to skip 21 | required: false 22 | default: 0 23 | --- 24 | 25 | Gets a list of challenges. 26 | 27 | --- 28 | 29 | **Remarks**: 30 | 31 | - Note that challenges are different from competitions - challenges are separate leaderboard structures that can be part of a competition (for example in the form of a qualifying session). 32 | 33 | --- 34 | 35 | **Example request**: 36 | 37 | ```plain 38 | GET https://meet.trackmania.nadeo.club/api/challenges?length=3 39 | ``` 40 | 41 | **Example response**: 42 | 43 | ```json 44 | [ 45 | { 46 | "id": 2388, 47 | "uid": "07f3ff0b-fc51-47ed-8b98-0380a8824d99", 48 | "name": "COTD 2023-02-07 #3 - Challenge", 49 | "scoreDirection": "ASC", 50 | "startDate": 1675850460, 51 | "endDate": 1675851360, 52 | "status": "INIT", 53 | "resultsVisibility": "PUBLIC", 54 | "creator": "afe7e1c1-7086-48f7-bde9-a7e320647510", 55 | "admins": [ 56 | "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 57 | "54e4dda4-522d-496f-8a8b-fe0d0b5a2a8f", 58 | "2116b392-d808-4264-923f-2bfcfa60a570", 59 | "6ce163d5-f240-4741-870b-f2adad843865", 60 | "a76653e1-998a-4c53-8a91-0a396e15bfb5" 61 | ], 62 | "nbServers": 0, 63 | "autoScale": false, 64 | "nbMaps": 1, 65 | "leaderboardId": 12307, 66 | "deletedOn": null, 67 | "leaderboardType": "SUM", 68 | "completeTimeout": 5 69 | }, 70 | { 71 | "id": 2387, 72 | "uid": "73650840-53eb-4921-a193-70b26f0ac789", 73 | "name": "COTD 2023-02-07 #2 - Challenge", 74 | "scoreDirection": "ASC", 75 | "startDate": 1675821660, 76 | "endDate": 1675822560, 77 | "status": "INIT", 78 | "resultsVisibility": "PUBLIC", 79 | "creator": "afe7e1c1-7086-48f7-bde9-a7e320647510", 80 | "admins": [ 81 | "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 82 | "54e4dda4-522d-496f-8a8b-fe0d0b5a2a8f", 83 | "2116b392-d808-4264-923f-2bfcfa60a570", 84 | "6ce163d5-f240-4741-870b-f2adad843865", 85 | "a76653e1-998a-4c53-8a91-0a396e15bfb5" 86 | ], 87 | "nbServers": 0, 88 | "autoScale": false, 89 | "nbMaps": 1, 90 | "leaderboardId": 12304, 91 | "deletedOn": null, 92 | "leaderboardType": "SUM", 93 | "completeTimeout": 5 94 | }, 95 | { 96 | "id": 2386, 97 | "uid": "063f5cfc-ade1-456e-9db3-f5ba3d4c8d3a", 98 | "name": "COTD 2023-02-07 #1 - Challenge", 99 | "scoreDirection": "ASC", 100 | "startDate": 1675792860, 101 | "endDate": 1675793760, 102 | "status": "HAS_SERVERS", 103 | "resultsVisibility": "PUBLIC", 104 | "creator": "afe7e1c1-7086-48f7-bde9-a7e320647510", 105 | "admins": [ 106 | "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 107 | "54e4dda4-522d-496f-8a8b-fe0d0b5a2a8f", 108 | "2116b392-d808-4264-923f-2bfcfa60a570", 109 | "6ce163d5-f240-4741-870b-f2adad843865", 110 | "a76653e1-998a-4c53-8a91-0a396e15bfb5" 111 | ], 112 | "nbServers": 0, 113 | "autoScale": false, 114 | "nbMaps": 1, 115 | "leaderboardId": 12301, 116 | "deletedOn": null, 117 | "leaderboardType": "SUM", 118 | "completeTimeout": 5 119 | } 120 | ] 121 | ``` 122 | -------------------------------------------------------------------------------- /docs/meet/challenges/leaderboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get challenge leaderboard 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/challenges/{challengeId}/leaderboard?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: challengeId 13 | type: string 14 | description: A valid challenge ID 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of leaderboard entries to retrieve 20 | required: false 21 | default: 10 22 | max: 100 23 | - name: offset 24 | type: integer 25 | description: The number of leaderboard entries to skip 26 | required: false 27 | default: 0 28 | --- 29 | 30 | Gets leaderboard entries for a challenge ID. 31 | 32 | --- 33 | 34 | **Remarks**: 35 | 36 | - Note that challenges are different from competitions - challenges are separate leaderboard structures that can be part of a competition (for example in the form of a qualifying session). 37 | - Typically challenges are used for qualifiers in larger competitions - the relevant `challengeId` can be retrieved using the [competition rounds endpoint](/meet/competitions/rounds). 38 | 39 | --- 40 | 41 | **Example request**: 42 | 43 | ```plain 44 | GET https://meet.trackmania.nadeo.club/api/challenges/409/leaderboard 45 | ``` 46 | 47 | **Example response**: 48 | 49 | ```json 50 | { 51 | "challengeId": 409, 52 | "cardinal": 399, 53 | "scoreUnit": "time", 54 | "results": [ 55 | { 56 | "points": 38106, 57 | "player": "b90e91eb-bd87-41fd-8c69-6560dbeedd2e", 58 | "score": 38106, 59 | "rank": 1, 60 | "zone": "World|Europe|Poland|Kujawsko-Pomorskie" 61 | }, 62 | { 63 | "points": 38156, 64 | "player": "dade4799-0761-41b7-8df1-cf413e5c8eef", 65 | "score": 38156, 66 | "rank": 2, 67 | "zone": "World|Asia|Brunei" 68 | }, 69 | { 70 | "points": 38206, 71 | "player": "d46fb45d-d422-47c9-9785-67270a311e25", 72 | "score": 38206, 73 | "rank": 3, 74 | "zone": "World|Europe|Czechia|Středočeský kraj" 75 | }, 76 | { 77 | "points": 38251, 78 | "player": "8f08302a-f670-463b-9f71-fbfacffb8bd1", 79 | "score": 38251, 80 | "rank": 4, 81 | "zone": "World|Europe|Germany|Saarland|Saarbrücken" 82 | }, 83 | { 84 | "points": 38252, 85 | "player": "70bd004b-b948-4a9c-9013-4282487f035b", 86 | "score": 38252, 87 | "rank": 5, 88 | "zone": "World|Europe|France|Nouvelle-Aquitaine|Pyrénées-Atlantiques" 89 | }, 90 | { 91 | "points": 38264, 92 | "player": "5c78b27a-908e-41f5-bce7-09e4367dbc0d", 93 | "score": 38264, 94 | "rank": 6, 95 | "zone": "World|North America|United States|Wisconsin" 96 | }, 97 | { 98 | "points": 38278, 99 | "player": "9688a134-3562-470c-a06d-2275da464643", 100 | "score": 38278, 101 | "rank": 7, 102 | "zone": "World|Europe|Finland" 103 | }, 104 | { 105 | "points": 38308, 106 | "player": "70e6f70b-5670-48d8-8551-fb8bb5181f03", 107 | "score": 38308, 108 | "rank": 8, 109 | "zone": "World|North America|Jamaica" 110 | }, 111 | { 112 | "points": 38321, 113 | "player": "6b14adfa-90d6-486f-8c32-66756d4c93d5", 114 | "score": 38321, 115 | "rank": 9, 116 | "zone": "World|Europe|Poland|Lubelskie" 117 | }, 118 | { 119 | "points": 38331, 120 | "player": "fcae33dd-70f2-4da1-b493-cd77c4399d0e", 121 | "score": 38331, 122 | "rank": 10, 123 | "zone": "World|South America|Brazil|São Paulo" 124 | } 125 | ] 126 | } 127 | ``` 128 | 129 | If a `challengeId` is invalid, the response will contain a `404` response code. 130 | -------------------------------------------------------------------------------- /docs/meet/challenges/map-records.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get challenge map records 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/challenges/{challengeId}/records/maps/{mapUid}?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: challengeId 13 | type: string 14 | description: A valid challenge ID 15 | required: true 16 | - name: mapUid 17 | type: string 18 | description: A valid map UID 19 | required: true 20 | query: 21 | - name: length 22 | type: integer 23 | description: The number of records to retrieve 24 | required: false 25 | default: 10 26 | max: 100 27 | - name: offset 28 | type: integer 29 | description: The number of records to skip 30 | required: false 31 | default: 0 32 | --- 33 | 34 | Gets map records for a challenge ID. 35 | 36 | --- 37 | 38 | **Remarks**: 39 | 40 | - Note that challenges are different from competitions - challenges are separate leaderboard structures that can be part of a competition (for example in the form of a qualifying session). 41 | - Typically challenges are used for qualifiers in larger competitions - the relevant `challengeId` can be retrieved using the [competition rounds endpoint](/meet/competitions/rounds). 42 | - This endpoint can be very similar to the [challenge leaderboard endpoint](/meet/challenges/leaderboard) - with the difference that you can retrieve map-specific rankings instead of the overall leaderboard. 43 | 44 | --- 45 | 46 | **Example request**: 47 | 48 | ```plain 49 | GET https://meet.trackmania.nadeo.club/api/challenges/409/records/maps/IM5eN8vx4kZfEedkLo2N5p548j3 50 | ``` 51 | 52 | **Example response**: 53 | 54 | ```json 55 | [ 56 | { 57 | "time": 38106, 58 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 59 | "player": "b90e91eb-bd87-41fd-8c69-6560dbeedd2e", 60 | "score": 38106, 61 | "rank": 1 62 | }, 63 | { 64 | "time": 38156, 65 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 66 | "player": "dade4799-0761-41b7-8df1-cf413e5c8eef", 67 | "score": 38156, 68 | "rank": 2 69 | }, 70 | { 71 | "time": 38206, 72 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 73 | "player": "d46fb45d-d422-47c9-9785-67270a311e25", 74 | "score": 38206, 75 | "rank": 3 76 | }, 77 | { 78 | "time": 38251, 79 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 80 | "player": "8f08302a-f670-463b-9f71-fbfacffb8bd1", 81 | "score": 38251, 82 | "rank": 4 83 | }, 84 | { 85 | "time": 38252, 86 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 87 | "player": "70bd004b-b948-4a9c-9013-4282487f035b", 88 | "score": 38252, 89 | "rank": 5 90 | }, 91 | { 92 | "time": 38264, 93 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 94 | "player": "5c78b27a-908e-41f5-bce7-09e4367dbc0d", 95 | "score": 38264, 96 | "rank": 6 97 | }, 98 | { 99 | "time": 38278, 100 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 101 | "player": "9688a134-3562-470c-a06d-2275da464643", 102 | "score": 38278, 103 | "rank": 7 104 | }, 105 | { 106 | "time": 38308, 107 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 108 | "player": "70e6f70b-5670-48d8-8551-fb8bb5181f03", 109 | "score": 38308, 110 | "rank": 8 111 | }, 112 | { 113 | "time": 38321, 114 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 115 | "player": "6b14adfa-90d6-486f-8c32-66756d4c93d5", 116 | "score": 38321, 117 | "rank": 9 118 | }, 119 | { 120 | "time": 38331, 121 | "uid": "IM5eN8vx4kZfEedkLo2N5p548j3", 122 | "player": "fcae33dd-70f2-4da1-b493-cd77c4399d0e", 123 | "score": 38331, 124 | "rank": 10 125 | } 126 | ] 127 | ``` 128 | 129 | If a `challengeId` is invalid, a `mapUid` is invalid, or there are no records for the combination of the two, the response will contain a `404` response code. 130 | -------------------------------------------------------------------------------- /docs/meet/club-competitions/club-competitions.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get club competitions 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/me/club-competitions?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | query: 12 | - name: length 13 | type: integer 14 | description: The number of competitions to retrieve 15 | required: false 16 | default: 0 17 | maximum: 100 18 | - name: offset 19 | type: integer 20 | description: The number of competitions to skip 21 | required: false 22 | default: 0 23 | --- 24 | 25 | Gets a list of competitions in clubs the current user is a member of. 26 | 27 | --- 28 | 29 | **Remarks**: 30 | 31 | - This endpoint is only useful with tokens authenticated through Ubisoft user accounts (as opposed to dedicated server accounts). 32 | - This endpoint requires the current user to own Club Access - otherwise they can't join any clubs, and this endpoint will always respond with an empty list. 33 | 34 | --- 35 | 36 | **Example request**: 37 | 38 | ```plain 39 | GET https://meet.trackmania.nadeo.club/api/me/club-competitions?length=1&offset=3 40 | ``` 41 | 42 | **Example response**: 43 | 44 | ```json 45 | { 46 | "clubCompetitions": [ 47 | { 48 | "activityId": 139313, 49 | "clubId": 548, 50 | "maxPlayers": 64, 51 | "type": "DEFAULT", 52 | "name": "RTG Cup", 53 | "logoUrl": "https://trackmania-prod-club-public.s3.eu-west-1.amazonaws.com/competitions/club/139313/logo/qx1flzj0darurljayib2.png", 54 | "verticalUrl": "https://trackmania-prod-club-public.s3.eu-west-1.amazonaws.com/competitions/club/139313/vertical/hokmohihqlhkzoeqtfnr.png" 55 | } 56 | ], 57 | "clubCompetitionsCount": 4 58 | } 59 | ``` 60 | 61 | If no relevant club competitions exist, the response will contain an empty array: 62 | 63 | ```json 64 | { 65 | "clubCompetitions": [], 66 | "clubCompetitionsCount": 0 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/meet/competition-matches/matches-for-round.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get matches for a competition round 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/rounds/{roundId}/matches?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: roundId 13 | type: string 14 | description: A valid round ID 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of matches to retrieve 20 | required: true 21 | default: 10 22 | max: 100 23 | - name: offset 24 | type: integer 25 | description: The number of matches to skip 26 | required: false 27 | default: 0 28 | --- 29 | 30 | Gets matches for a given round in a competition. 31 | 32 | --- 33 | 34 | **Remarks**: 35 | 36 | - Note that the match IDs in the response are competition match IDs to be used in [competition match endpoints](/meet/competition-matches) - they are not equivalent to the numerical match IDs used in the [match endpoints](/meet/matches). To use those endpoints based on the response from this endpoint, use the `clubMatchLiveId` field as an identifier. 37 | 38 | --- 39 | 40 | **Example request**: 41 | 42 | ```plain 43 | GET https://meet.trackmania.nadeo.club/api/rounds/9078/matches 44 | ``` 45 | 46 | **Example response**: 47 | 48 | ```json 49 | { 50 | "matches": [ 51 | { 52 | "id": 38449, 53 | "name": "Baltic Weekly #2 - Quarter Finals - 1", 54 | "clubMatchLiveId": "LID-MTCH-x1accvkawhlput1", 55 | "position": 0, 56 | "isCompleted": true, 57 | "tags": [], 58 | "deletedOn": null 59 | }, 60 | { 61 | "id": 38450, 62 | "name": "Baltic Weekly #2 - Quarter Finals - 2", 63 | "clubMatchLiveId": "LID-MTCH-tmiims2yypi0wvl", 64 | "position": 1, 65 | "isCompleted": true, 66 | "tags": [], 67 | "deletedOn": null 68 | }, 69 | { 70 | "id": 38451, 71 | "name": "Baltic Weekly #2 - Quarter Finals - 3", 72 | "clubMatchLiveId": "LID-MTCH-s0rvc5jgmykdzxu", 73 | "position": 2, 74 | "isCompleted": true, 75 | "tags": [], 76 | "deletedOn": null 77 | }, 78 | { 79 | "id": 38452, 80 | "name": "Baltic Weekly #2 - Quarter Finals - 4", 81 | "clubMatchLiveId": "LID-MTCH-jzk5mckt5e5udej", 82 | "position": 3, 83 | "isCompleted": true, 84 | "tags": [], 85 | "deletedOn": null 86 | } 87 | ] 88 | } 89 | ``` 90 | 91 | If a `roundId` is invalid, the response will contain a `404` response code. 92 | -------------------------------------------------------------------------------- /docs/meet/competition-matches/player-matches.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get competition matches for player 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/competitions/{competitionId}/participants/{accountId}/matches 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: competitionId 13 | type: string 14 | description: A valid competition ID 15 | required: true 16 | - name: accountId 17 | type: string 18 | description: A valid account ID 19 | required: true 20 | --- 21 | 22 | Gets matches for a player in the context of a competition. 23 | 24 | --- 25 | 26 | **Remarks**: 27 | 28 | - There are two different competition IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-COMP-`. 29 | 30 | --- 31 | 32 | **Example request**: 33 | 34 | ```plain 35 | GET https://meet.trackmania.nadeo.club/api/competitions/4621/participants/e07e9ea9-daa5-4496-9908-9680e35da02b/matches 36 | ``` 37 | 38 | **Example response**: 39 | 40 | ```json 41 | [ 42 | { 43 | "matchLiveId": "LID-MTCH-dz3d2qsgeqsy55q", 44 | "roundPosition": 0, 45 | "results": [ 46 | { 47 | "participant": "0da0a251-20e8-4219-86eb-7d9c52847779", 48 | "rank": null, 49 | "score": null, 50 | "zone": "World", 51 | "team": "a6543d8d-b277-4029-92e5-c08ba1d6166a" 52 | }, 53 | { 54 | "participant": "e07e9ea9-daa5-4496-9908-9680e35da02b", 55 | "rank": null, 56 | "score": null, 57 | "zone": "World", 58 | "team": "a6543d8d-b277-4029-92e5-c08ba1d6166a" 59 | } 60 | ], 61 | "scoreUnit": "point", 62 | "teams": [] 63 | }, 64 | ... 65 | { 66 | "matchLiveId": "LID-MTCH-h3t0o1ivvjgbngw", 67 | "roundPosition": 5, 68 | "results": [ 69 | { 70 | "participant": "0da0a251-20e8-4219-86eb-7d9c52847779", 71 | "rank": 1, 72 | "score": 0, 73 | "zone": "World", 74 | "team": "a6543d8d-b277-4029-92e5-c08ba1d6166a" 75 | }, 76 | { 77 | "participant": "e07e9ea9-daa5-4496-9908-9680e35da02b", 78 | "rank": 2, 79 | "score": 0, 80 | "zone": "World", 81 | "team": "a6543d8d-b277-4029-92e5-c08ba1d6166a" 82 | }, 83 | { 84 | "participant": "9f0dae68-3ae7-4396-bb97-44822c302b7c", 85 | "rank": 3, 86 | "score": 0, 87 | "zone": "World", 88 | "team": "ce1f8c64-fb80-4411-bef1-ce6cc2ef6e52" 89 | }, 90 | { 91 | "participant": "54c7bd69-67f6-4544-902a-41c6ed4e0b3a", 92 | "rank": 4, 93 | "score": 0, 94 | "zone": "World", 95 | "team": "ce1f8c64-fb80-4411-bef1-ce6cc2ef6e52" 96 | } 97 | ], 98 | "scoreUnit": "point", 99 | "teams": [] 100 | } 101 | ] 102 | ``` 103 | 104 | If a `competitionId` is invalid, the response will contain a `404` response code. 105 | 106 | If an `accountId` is invalid or the player did not participate in the competition, the response will contain an empty array. 107 | -------------------------------------------------------------------------------- /docs/meet/competition-matches/results.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get competition match results 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matches/{compMatchId}/results?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: compMatchId 13 | type: string 14 | description: A valid competition match ID 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of results to retrieve 20 | required: false 21 | default: 10 22 | max: 255 23 | - name: offset 24 | type: integer 25 | description: The number of results to skip 26 | required: false 27 | default: 0 28 | --- 29 | 30 | Gets results for a given competition match ID. 31 | 32 | --- 33 | 34 | **Remarks**: 35 | 36 | - This endpoint only supports competition match IDs, which are different from regular match IDs (as found in [the match endpoints](/meet/matches)). They are numerical and have to be retrieved from a competition's rounds (see [here](/meet/competition-matches/matches-for-round)). 37 | - If the match does not use teams, the `teams` field will be an empty array, and the `teamPosition` field for each player will be `null`. 38 | - For proper team mappings and team names, refer to [the competition teams endpoint](/meet/competitions/teams). 39 | 40 | --- 41 | 42 | **Example request**: 43 | 44 | ```plain 45 | GET https://meet.trackmania.nadeo.club/api/matches/54430/results 46 | ``` 47 | 48 | **Example response**: 49 | 50 | ```json 51 | { 52 | "matchLiveId": "LID-MTCH-wnf4y3emu43rxnk", 53 | "roundPosition": 0, 54 | "results": [ 55 | { 56 | "participant": "7c02bdeb-92dc-4435-b07b-647e0d5699a9", 57 | "rank": 1, 58 | "score": 0, 59 | "zone": "World", 60 | "team": "0c908d55-efa5-401a-b5ba-5afd1eac7686" 61 | }, 62 | { 63 | "participant": "0120bf0b-b567-4224-bd6e-a0b4da089905", 64 | "rank": 2, 65 | "score": 0, 66 | "zone": "World", 67 | "team": "537a040c-dd37-4294-badf-ec7a71b0a4bf" 68 | }, 69 | { 70 | "participant": "a61fffac-b203-4e37-8d32-0ae1b772578f", 71 | "rank": 3, 72 | "score": 0, 73 | "zone": "World", 74 | "team": "0c908d55-efa5-401a-b5ba-5afd1eac7686" 75 | }, 76 | { 77 | "participant": "3905ba40-a668-4e6a-8a95-9591eb20e673", 78 | "rank": 4, 79 | "score": 0, 80 | "zone": "World", 81 | "team": "537a040c-dd37-4294-badf-ec7a71b0a4bf" 82 | } 83 | ], 84 | "scoreUnit": "point", 85 | "teams": [ 86 | { 87 | "position": 0, 88 | "team": "0c908d55-efa5-401a-b5ba-5afd1eac7686", 89 | "rank": 1, 90 | "score": 2 91 | }, 92 | { 93 | "position": 1, 94 | "team": "537a040c-dd37-4294-badf-ec7a71b0a4bf", 95 | "rank": 2, 96 | "score": 0 97 | } 98 | ] 99 | } 100 | ``` 101 | 102 | If a `compMatchId` is invalid (or the match information is not available), the response will contain a `404` response code. 103 | -------------------------------------------------------------------------------- /docs/meet/competitions/leaderboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get competition leaderboard 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/competitions/{competitionId}/leaderboard?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: competitionId 13 | type: string 14 | description: A valid competition ID 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of participants to retrieve 20 | required: false 21 | default: 10 22 | max: 255 23 | - name: offset 24 | type: integer 25 | description: The number of participants to skip 26 | required: false 27 | default: 0 28 | --- 29 | 30 | Gets leaderboard for a competition ID. 31 | 32 | --- 33 | 34 | **Remarks**: 35 | 36 | - There are two different competition IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-COMP-`. 37 | - If a competition hasn't started yet, all `score` values will be `0`, but there will still be `rank` values assigned to each player. 38 | 39 | --- 40 | 41 | **Example request**: 42 | 43 | ```plain 44 | GET https://meet.trackmania.nadeo.club/api/competitions/3629/leaderboard?length=100 45 | ``` 46 | 47 | **Example response**: 48 | 49 | ```json 50 | [ 51 | { 52 | "participant": "da4642f9-6acf-43fe-88b6-b120ff1308ba", 53 | "rank": 1, 54 | "score": 2418, 55 | "zone": "World|Europe|Belgium|Liège" 56 | }, 57 | { 58 | "participant": "aceb463a-ed8e-47d6-bc8d-025c229aca5b", 59 | "rank": 2, 60 | "score": 2417, 61 | "zone": "World|Europe|France|Auvergne-Rhône-Alpes|Rhône" 62 | }, 63 | { 64 | "participant": "87e4afbf-fb54-4d60-9ce1-b0698beab097", 65 | "rank": 3, 66 | "score": 2416, 67 | "zone": "World|Europe|Slovakia" 68 | }, 69 | ... 70 | { 71 | "participant": "88347e06-f817-4643-b965-0f1e5fcb753c", 72 | "rank": 98, 73 | "score": 2321, 74 | "zone": "World|Europe|France|Île-de-France|Yvelines" 75 | }, 76 | { 77 | "participant": "edb9dfe7-d7cf-4add-8a5e-d992fa2a35bb", 78 | "rank": 99, 79 | "score": 2320, 80 | "zone": "World|Europe|Italy|Piemonte" 81 | }, 82 | { 83 | "participant": "0d2596bf-b3f4-4b36-8dab-f66c34d8ec74", 84 | "rank": 100, 85 | "score": 2319, 86 | "zone": "World|Europe|Germany|Baden-Württemberg|Stuttgart" 87 | } 88 | ] 89 | ``` 90 | 91 | If a `competitionId` is invalid, the response will contain a `404` response code. 92 | -------------------------------------------------------------------------------- /docs/meet/competitions/participants.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get competition participants 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/competitions/{competitionId}/participants?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: competitionId 13 | type: string 14 | description: A valid competition ID 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of participants to retrieve 20 | required: false 21 | default: 10 22 | max: 255 23 | - name: offset 24 | type: integer 25 | description: The number of participants to skip 26 | required: false 27 | default: 0 28 | --- 29 | 30 | Gets participants for a competition ID. 31 | 32 | --- 33 | 34 | **Remarks**: 35 | 36 | - There are two different competition IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-COMP-`. 37 | 38 | --- 39 | 40 | **Example request**: 41 | 42 | ```plain 43 | GET https://meet.trackmania.nadeo.club/api/competitions/332/participants?length=5 44 | ``` 45 | 46 | **Example response**: 47 | 48 | ```json 49 | [ 50 | { 51 | "participant": "05c82ef9-e6a8-4c83-9897-f747ce51fad5", 52 | "zone": "World", 53 | "registration": 1619860645, 54 | "seed": null, 55 | "addedBy": "6969eb50-f6e3-4fb5-876e-f264792e3240", 56 | "team": null, 57 | "checkInDate": null, 58 | "groupId": null, 59 | "skillLevel": null 60 | }, 61 | { 62 | "participant": "81fbf9cf-f767-4d1b-a338-8b535de6d1e2", 63 | "zone": "World", 64 | "registration": 1619860642, 65 | "seed": null, 66 | "addedBy": "6969eb50-f6e3-4fb5-876e-f264792e3240", 67 | "team": null, 68 | "checkInDate": null, 69 | "groupId": null, 70 | "skillLevel": null 71 | }, 72 | { 73 | "participant": "078cb393-1bf8-49dd-b26b-a03771e13144", 74 | "zone": "World", 75 | "registration": 1619860638, 76 | "seed": null, 77 | "addedBy": "6969eb50-f6e3-4fb5-876e-f264792e3240", 78 | "team": null, 79 | "checkInDate": null, 80 | "groupId": null, 81 | "skillLevel": null 82 | }, 83 | { 84 | "participant": "041d942b-fc48-407c-be97-f32ec9a7d782", 85 | "zone": "World", 86 | "registration": 1619860635, 87 | "seed": null, 88 | "addedBy": "6969eb50-f6e3-4fb5-876e-f264792e3240", 89 | "team": null, 90 | "checkInDate": null, 91 | "groupId": null, 92 | "skillLevel": null 93 | }, 94 | { 95 | "participant": "a05f508b-abdd-48a1-aa7c-f85039905e33", 96 | "zone": "World", 97 | "registration": 1619860632, 98 | "seed": null, 99 | "addedBy": "6969eb50-f6e3-4fb5-876e-f264792e3240", 100 | "team": null, 101 | "checkInDate": null, 102 | "groupId": null, 103 | "skillLevel": null 104 | } 105 | ] 106 | ``` 107 | 108 | If a `competitionId` is invalid, the response will contain a `404` response code. 109 | -------------------------------------------------------------------------------- /docs/meet/competitions/rounds.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get competition rounds 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/competitions/{competitionId}/rounds 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: competitionId 13 | type: string 14 | description: A valid competition ID 15 | required: true 16 | --- 17 | 18 | Gets rounds details for a competition ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - There are two different competition IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-COMP-`. 25 | - If a round has a qualifier attached to it (e.g. the TA qualifier in COTD), its associated `challengeId` can be found in the `qualifierChallengeId` field. This is what you'd use to get more information about the qualifier, for example when [getting the qualifier leaderboards](/meet/challenges/leaderboard). 26 | - To retrieve a round's matches (and their results), you can use [the round matches endpoint](/meet/competition-matches/matches-for-round). 27 | 28 | --- 29 | 30 | **Example request**: 31 | 32 | ```plain 33 | GET https://meet.trackmania.nadeo.club/api/competitions/3633/rounds 34 | ``` 35 | 36 | **Example response**: 37 | 38 | ```json 39 | [ 40 | { 41 | "id": 9078, 42 | "position": 0, 43 | "name": "Quarter Finals", 44 | "startDate": 1663425300, 45 | "endDate": 1663427100, 46 | "lockDate": null, 47 | "status": null, 48 | "isLocked": false, 49 | "autoNeedsMatches": true, 50 | "matchScoreDirection": "DESC", 51 | "leaderboardComputeType": "BRACKET", 52 | "teamLeaderboardComputeType": null, 53 | "deletedOn": null, 54 | "nbMatches": 0, 55 | "qualifierChallengeId": 1805, 56 | "trainingChallengeId": null 57 | }, 58 | { 59 | "id": 9079, 60 | "position": 1, 61 | "name": "SemiFinals", 62 | "startDate": 1663427400, 63 | "endDate": 1663429200, 64 | "lockDate": null, 65 | "status": null, 66 | "isLocked": false, 67 | "autoNeedsMatches": true, 68 | "matchScoreDirection": "DESC", 69 | "leaderboardComputeType": "BRACKET", 70 | "teamLeaderboardComputeType": null, 71 | "deletedOn": null, 72 | "nbMatches": 0, 73 | "qualifierChallengeId": null, 74 | "trainingChallengeId": null 75 | }, 76 | { 77 | "id": 9080, 78 | "position": 2, 79 | "name": "FINAL", 80 | "startDate": 1663429500, 81 | "endDate": 1663431300, 82 | "lockDate": null, 83 | "status": null, 84 | "isLocked": false, 85 | "autoNeedsMatches": true, 86 | "matchScoreDirection": "DESC", 87 | "leaderboardComputeType": "BRACKET", 88 | "teamLeaderboardComputeType": null, 89 | "deletedOn": null, 90 | "nbMatches": 0, 91 | "qualifierChallengeId": null, 92 | "trainingChallengeId": null 93 | } 94 | ] 95 | ``` 96 | 97 | If a `competitionId` is invalid, the response will contain a `404` response code. 98 | -------------------------------------------------------------------------------- /docs/meet/competitions/teams.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get competition teams 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/competitions/{competitionId}/mode-teams 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: competitionId 13 | type: string 14 | description: A valid competition ID 15 | required: true 16 | --- 17 | 18 | Gets teams for a competition ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - There are two different competition IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-COMP-`. 25 | 26 | --- 27 | 28 | **Example request**: 29 | 30 | ```plain 31 | GET https://meet.trackmania.nadeo.club/api/competitions/4621/mode-teams 32 | ``` 33 | 34 | **Example response**: 35 | 36 | ```json 37 | [ 38 | { 39 | "Id": "1a95ea05-6c59-4839-9777-0ce807b2cc76", 40 | "Name": "Southern Speedsters", 41 | "Players": [ 42 | { 43 | "AccountId": "19964586-33bd-4645-8ceb-2ca9f2195060" 44 | }, 45 | { 46 | "AccountId": "fd6ca975-d21b-43db-a416-cd36a1be75fc" 47 | } 48 | ] 49 | }, 50 | { 51 | "Id": "6b38c00f-b820-437b-9871-0f6975f717e3", 52 | "Name": "Orgless", 53 | "Players": [ 54 | { 55 | "AccountId": "1699cffd-862d-4ae0-bbd4-0efbb40ef28b" 56 | }, 57 | { 58 | "AccountId": "3a88d4bc-a2a5-4b38-9fd6-f05c02ef159a" 59 | } 60 | ] 61 | }, 62 | { 63 | "Id": "7bb198d0-2f69-4265-b467-dc0fa8c0a9f0", 64 | "Name": "PF Racing", 65 | "Players": [ 66 | { 67 | "AccountId": "3ca1d081-3872-4a7d-ad8f-a3e785bfbfff" 68 | }, 69 | { 70 | "AccountId": "ac424f5e-5612-4a44-8b87-6403be2b690f" 71 | } 72 | ] 73 | }, 74 | { 75 | "Id": "a6543d8d-b277-4029-92e5-c08ba1d6166a", 76 | "Name": "F10", 77 | "Players": [ 78 | { 79 | "AccountId": "0da0a251-20e8-4219-86eb-7d9c52847779" 80 | }, 81 | { 82 | "AccountId": "e07e9ea9-daa5-4496-9908-9680e35da02b" 83 | } 84 | ] 85 | }, 86 | { 87 | "Id": "ce1f8c64-fb80-4411-bef1-ce6cc2ef6e52", 88 | "Name": "Molotov Gaming", 89 | "Players": [ 90 | { 91 | "AccountId": "54c7bd69-67f6-4544-902a-41c6ed4e0b3a" 92 | }, 93 | { 94 | "AccountId": "9f0dae68-3ae7-4396-bb97-44822c302b7c" 95 | } 96 | ] 97 | }, 98 | { 99 | "Id": "d88996af-5af7-48a0-83ba-1fd0ee2aa5ea", 100 | "Name": "Camurun Icinde", 101 | "Players": [ 102 | { 103 | "AccountId": "9d4f5763-1c07-412e-875c-d9277b102d52" 104 | }, 105 | { 106 | "AccountId": "df3fcb0e-e187-4634-b205-c56e4f52a20b" 107 | } 108 | ] 109 | } 110 | ] 111 | ``` 112 | 113 | If a `competitionId` is invalid or the competition doesn't have any teams, the response will contain an empty array. 114 | -------------------------------------------------------------------------------- /docs/meet/cup-of-the-day/current.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get current COTD 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/cup-of-the-day/current 7 | 8 | audience: NadeoLiveServices 9 | --- 10 | 11 | Gets details for the currently ongoing Cup of the Day. 12 | 13 | --- 14 | 15 | **Remarks**: 16 | 17 | - This endpoint only returns data about the cross-platform/"crossplay" COTD. Platform-specific COTD instances are not included. 18 | - If there is no COTD currently happening, this endpoint will respond with status code `204` (No content). 19 | 20 | --- 21 | 22 | **Example request**: 23 | 24 | ```plain 25 | GET https://meet.trackmania.nadeo.club/api/cup-of-the-day/current 26 | ``` 27 | 28 | **Example response**: 29 | 30 | ```json 31 | { 32 | "id": 3872, 33 | "edition": 1, 34 | "competition": { 35 | "id": 9263, 36 | "liveId": "LID-COMP-pdejsjire2fz2ve", 37 | "creator": "afe7e1c1-7086-48f7-bde9-a7e320647510", 38 | "name": "COTD 2023-08-27 #1", 39 | "participantType": "PLAYER", 40 | "description": null, 41 | "registrationStart": null, 42 | "registrationEnd": null, 43 | "startDate": 1693156590, 44 | "endDate": 1693163790, 45 | "matchesGenerationDate": 1693156565, 46 | "nbPlayers": 3404, 47 | "spotStructure": "{\"version\":1,\"rounds\":[{\"matchGeneratorData\":{\"matchSize\":64,\"matchGeneratorType\":\"daily_cup\"},\"matchGeneratorType\":\"daily_cup\"}]}", 48 | "leaderboardId": 23684, 49 | "manialink": null, 50 | "rulesUrl": null, 51 | "streamUrl": null, 52 | "websiteUrl": null, 53 | "logoUrl": null, 54 | "verticalUrl": null, 55 | "allowedZones": [], 56 | "deletedOn": null, 57 | "autoNormalizeSeeds": true, 58 | "region": "eu-west", 59 | "autoGetParticipantSkillLevel": "DISABLED", 60 | "matchAutoMode": "ENABLED", 61 | "partition": "crossplay" 62 | }, 63 | "challenge": { 64 | "id": 4595, 65 | "uid": "4c053e36-b356-431e-af49-081b351438f0", 66 | "name": "COTD 2023-08-27 #1 - Challenge", 67 | "scoreDirection": "ASC", 68 | "startDate": 1693155660, 69 | "endDate": 1693156560, 70 | "status": "HAS_SERVERS", 71 | "resultsVisibility": "PUBLIC", 72 | "creator": "afe7e1c1-7086-48f7-bde9-a7e320647510", 73 | "admins": [ 74 | "0060a0c1-2e62-41e7-9db7-c86236af3ac4", 75 | "54e4dda4-522d-496f-8a8b-fe0d0b5a2a8f", 76 | "2116b392-d808-4264-923f-2bfcfa60a570", 77 | "6ce163d5-f240-4741-870b-f2adad843865", 78 | "a76653e1-998a-4c53-8a91-0a396e15bfb5" 79 | ], 80 | "nbServers": 0, 81 | "autoScale": false, 82 | "nbMaps": 1, 83 | "leaderboardId": 23682, 84 | "deletedOn": null, 85 | "leaderboardType": "SUM", 86 | "completeTimeout": 5 87 | }, 88 | "startDate": 1693155660, 89 | "endDate": 1693163790, 90 | "deletedOn": null 91 | } 92 | ``` 93 | -------------------------------------------------------------------------------- /docs/meet/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Meet API 3 | category: reference 4 | --- 5 | 6 | # Meet API 7 | 8 | The Meet API contains endpoints for interacting with competitions, matchmaking and other match infrastructure. 9 | 10 | As of July 2023, it's the new umbrella API for the previous `competition`, `matchmaking` and `club` domains. 11 | 12 | All of its endpoints require a token with the `NadeoLiveServices` audience. 13 | 14 | ## Deprecations 15 | 16 | - July 2023: The `/participants` endpoint for competition matches has been removed during the move to the central `meet` API - to retrieve a competition match's players, it's recommended to use the [competition match result endpoint](/meet/competition-matches/results). 17 | - January 2024: The Meet API has moved from the `NadeoClubServices` audience to `NadeoLiveServices`. The old audience will continue to work but will eventually get deprecated. 18 | -------------------------------------------------------------------------------- /docs/meet/matches/match.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get match information 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matches/{matchId} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: matchId 13 | type: string 14 | description: A valid match ID 15 | required: true 16 | --- 17 | 18 | Gets match information for a given match ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - Match information is only stored on Nadeo's servers for about a month - afterwards, requesting it will only result in a `404` response code. 25 | - There are two different match IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-MTCH-`. 26 | - As of February 2023, this endpoint no longer included any `serverConfig` data. You can find the previous response structure at the bottom of the page for reference. 27 | - As of 2024-01-22, the endpoint's response was adjusted to again include the script name and related maps (identified by their `mapUid`). 28 | 29 | --- 30 | 31 | **Example request**: 32 | 33 | ```plain 34 | GET https://meet.trackmania.nadeo.club/api/matches/8410984 35 | ``` 36 | 37 | **Example response**: 38 | 39 | ```json 40 | { 41 | "id": 8410984, 42 | "liveId": "LID-MTCH-ahrwj00ccqenvrx", 43 | "name": "Official 3v3 - match", 44 | "startDate": 1705929747, 45 | "endDate": 1705931547, 46 | "status": "ONGOING", 47 | "participantType": "team", 48 | "joinLink": "#join=TmnMwMfaQ0m4HzkwXKOOxA@Trackmania", 49 | "serverStatus": "STARTED", 50 | "manialink": null, 51 | "publicConfig": { 52 | "script": "TrackMania/TM_Teams_Matchmaking_Online.Script.txt", 53 | "maps": ["OsaDprWoMJSbmNVGSVz9_W7ue0d"] 54 | } 55 | } 56 | ``` 57 | 58 | If a `matchId` is invalid, the response will contain a `404` response code. 59 | 60 | --- 61 | 62 | This endpoint was changed in February 2023 to no longer include the `serverConfig` along with the removal of several other fields - the previous response structure can be found below for reference. 63 | 64 | **Request**: 65 | 66 | ```plain 67 | GET https://club.trackmania.nadeo.club/api/matches/3018551 68 | ``` 69 | 70 | **Response**: 71 | 72 | ```json 73 | { 74 | "id": 3018551, 75 | "liveId": "LID-MTCH-hbwk5tnbsddmnhd", 76 | "name": "Official 3v3 - match", 77 | "startDate": 1663417867, 78 | "endDate": 1663419667, 79 | "scoreDirection": "DESC", 80 | "serverConfig": { 81 | "name": "default", 82 | "script": "TrackMania/TM_Teams_Matchmaking_Online.Script.txt", 83 | "scriptSettings": { 84 | "S_WarmUpNb": 1, 85 | "S_WarmUpDuration": 30, 86 | "S_UseCustomPointsRepartition": true, 87 | "S_NoRoundTie": true, 88 | "S_BalanceScore": true, 89 | "S_PointsRepartition": "6,5,4,3,2,1", 90 | "S_DecoImageUrl_WhoAmIUrl": "", 91 | "S_ScriptEnvironment": "test", 92 | "S_MatchmakingId": "2" 93 | }, 94 | "password": "", 95 | "maxPlayers": 10, 96 | "maxSpectators": 10, 97 | "plugin": "server-plugins/Club/ClubPlugin.Script.txt", 98 | "pluginSettings": { 99 | "S_ImmutableMatch": true, 100 | "S_AutoStartMode": "light", 101 | "S_EnableMatchSheet": false 102 | }, 103 | "maps": ["WDOdgubY3FTn3pKE8enDMhaEs_3"], 104 | "voteRatios": { 105 | "ban": -1, 106 | "kick": -1, 107 | "restartMap": -1, 108 | "nextMap": -1, 109 | "jumpToMapIndex": -1, 110 | "jumpToMapIdent": -1, 111 | "setNextMapIndex": -1, 112 | "setNextMapIdent": -1, 113 | "autoTeamBalance": -1, 114 | "setModeScriptSettings": -1 115 | } 116 | }, 117 | "serverId": 4092404, 118 | "serverStatus": "DELETED", 119 | "joinLink": "#join=oCwp9D8ISxGEyAIDlBuk2Q@Trackmania", 120 | "status": "COMPLETED", 121 | "participantType": "team", 122 | "manialink": "", 123 | "deletedOn": null, 124 | "group": "matchmaking_2", 125 | "policy": null, 126 | "region": null, 127 | "autoMode": "ENABLED" 128 | } 129 | ``` 130 | -------------------------------------------------------------------------------- /docs/meet/matches/participants.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get match participants 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matches/{matchId}/participants 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: matchId 13 | type: string 14 | description: A valid match ID 15 | required: true 16 | --- 17 | 18 | Gets players for a given match ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - Match information is only stored on Nadeo's servers for about a month - afterwards, requesting it will only result in a `404` response code. 25 | - There are two different match IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-MTCH-`. 26 | 27 | --- 28 | 29 | **Example request**: 30 | 31 | ```plain 32 | GET https://meet.trackmania.nadeo.club/api/matches/3018551/participants 33 | ``` 34 | 35 | **Example response**: 36 | 37 | ```json 38 | [ 39 | { 40 | "participant": "d1248c49-9afc-4a94-9e6d-941d3e954496", 41 | "position": 0, 42 | "teamPosition": 0, 43 | "rank": 5, 44 | "score": 12, 45 | "mvp": false, 46 | "leaver": null, 47 | "eliminated": false 48 | }, 49 | { 50 | "participant": "7f2886b1-a735-46d6-8c07-0d6975b468e4", 51 | "position": 1, 52 | "teamPosition": 0, 53 | "rank": 6, 54 | "score": 10, 55 | "mvp": false, 56 | "leaver": null, 57 | "eliminated": false 58 | }, 59 | { 60 | "participant": "d83627a4-2c7c-4be9-969c-1ab41f2f79fa", 61 | "position": 2, 62 | "teamPosition": 0, 63 | "rank": 3, 64 | "score": 17, 65 | "mvp": false, 66 | "leaver": null, 67 | "eliminated": false 68 | }, 69 | { 70 | "participant": "dc203ffc-bab7-4971-bfb3-dec83db1fa4e", 71 | "position": 3, 72 | "teamPosition": 1, 73 | "rank": 2, 74 | "score": 23, 75 | "mvp": false, 76 | "leaver": null, 77 | "eliminated": false 78 | }, 79 | { 80 | "participant": "6a7a889f-cbff-4910-b369-a4201de53cb8", 81 | "position": 4, 82 | "teamPosition": 1, 83 | "rank": 1, 84 | "score": 27, 85 | "mvp": true, 86 | "leaver": null, 87 | "eliminated": false 88 | }, 89 | { 90 | "participant": "bb961ea9-bb72-49c2-9294-fb0a34fb7591", 91 | "position": 5, 92 | "teamPosition": 1, 93 | "rank": 4, 94 | "score": 16, 95 | "mvp": false, 96 | "leaver": null, 97 | "eliminated": false 98 | } 99 | ] 100 | ``` 101 | 102 | If a `matchId` is invalid, the response will contain a `404` response code. 103 | -------------------------------------------------------------------------------- /docs/meet/matches/teams.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get match teams 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matches/{matchId}/teams 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: matchId 13 | type: string 14 | description: A valid match ID 15 | required: true 16 | --- 17 | 18 | Gets team information for a given match ID. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - Match information is only stored on Nadeo's servers for about a month - afterwards, requesting it will only result in a `404` response code. 25 | - There are two different match IDs which are both supported by this endpoint - the primary `id` is always numerical, while the `liveId` is a string typically starting with `"LID-MTCH-`. 26 | 27 | --- 28 | 29 | **Example request**: 30 | 31 | ```plain 32 | GET https://meet.trackmania.nadeo.club/api/matches/3018551/teams 33 | ``` 34 | 35 | **Example response**: 36 | 37 | ```json 38 | [ 39 | { 40 | "position": 0, 41 | "score": 0, 42 | "rank": 2 43 | }, 44 | { 45 | "position": 1, 46 | "score": 5, 47 | "rank": 1 48 | } 49 | ] 50 | ``` 51 | 52 | If a `matchId` is invalid, the response will contain a `404` response code. 53 | -------------------------------------------------------------------------------- /docs/meet/matchmaking/divisions.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get matchmaking divisions 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matchmaking/{matchmakingType}/division/display-rules 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: matchmakingType 13 | type: integer 14 | description: The ID of the matchmaking type 15 | required: true 16 | --- 17 | 18 | Gets division definitions/rules for the different matchmaking modes. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | 24 | - The `matchmakingType` parameter is typically one of `2` (Ranked) or `3` (Royal). For a dynamic way of retrieving those IDs see [the matchmaking summary endpoint](/meet/matchmaking/summary). 25 | 26 | --- 27 | 28 | **Example request**: 29 | 30 | ```plain 31 | GET https://meet.trackmania.nadeo.club/api/matchmaking/2/division/display-rules 32 | ``` 33 | 34 | **Example response**: 35 | 36 | ```json 37 | { 38 | "divisions": [ 39 | { 40 | "id": "d9a8485d-4f43-402b-af9f-a1b819678723", 41 | "position": 1, 42 | "displayRuleType": "points_range", 43 | "displayRuleMinimumPoints": 0, 44 | "displayRuleMaximumPoints": 299, 45 | "displayRuleMinimumRank": null, 46 | "displayRuleMinimumVictories": null, 47 | "displayRuleMaximumVictories": null 48 | }, 49 | ... 50 | { 51 | "id": "bd7282b7-04c4-4c25-b672-1f538ef7b5f9", 52 | "position": 13, 53 | "displayRuleType": "minimum_rank_and_points", 54 | "displayRuleMinimumPoints": 4000, 55 | "displayRuleMaximumPoints": null, 56 | "displayRuleMinimumRank": 10, 57 | "displayRuleMinimumVictories": null, 58 | "displayRuleMaximumVictories": null 59 | } 60 | ] 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/meet/matchmaking/player-ranking.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player matchmaking ranks 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matchmaking/{matchmakingType}/leaderboard/players?players[]={accountID} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: matchmakingType 13 | type: integer 14 | description: The ID of the matchmaking type 15 | required: true 16 | query: 17 | - name: accountID 18 | type: string 19 | description: A valid account ID 20 | required: true 21 | --- 22 | 23 | Gets matchmaking ranks (for the specified type) for the requested players. 24 | 25 | --- 26 | 27 | **Remarks**: 28 | 29 | - The `matchmakingType` parameter is typically one of `2` (Ranked) or `3` (Royal). For a dynamic way of retrieving those IDs see [the matchmaking summary endpoint](/meet/matchmaking/summary). 30 | - The `cardinal` field in the response is the total number of players in the ranking. 31 | - To get data for more than one account at a time, you can send an array of values instead of a single value - see the second example below. 32 | - This endpoint has no intrinsic limit on the number of account IDs requested, but it will return a `414` error if the request URI length is 8220 characters or more (corresponding to just over 150 account IDs, depending on how you encode the URI). 33 | 34 | --- 35 | 36 | **Example request**: 37 | 38 | ```plain 39 | https://meet.trackmania.nadeo.club/api/matchmaking/2/leaderboard/players?players[]=f7fab1a3-3bcc-4ffa-8ce3-45cea7ab89c3 40 | ``` 41 | 42 | **Example response**: 43 | 44 | ```json 45 | { 46 | "matchmakingId": 2, 47 | "cardinal": 1158029, 48 | "results": [ 49 | { 50 | "player": "f7fab1a3-3bcc-4ffa-8ce3-45cea7ab89c3", 51 | "rank": 924, 52 | "score": 2431 53 | } 54 | ] 55 | } 56 | ``` 57 | 58 | To retrieve data for more than one account at once, send the `accountID` values as follows: 59 | 60 | ```plain 61 | GET https://matchmaking.trackmania.nadeo.club/api/matchmaking/2/leaderboard/players?players[]=f7fab1a3-3bcc-4ffa-8ce3-45cea7ab89c3&players[]=f8f7c280-8419-472e-9329-6436fe3d04c3 62 | ``` 63 | 64 | If the requested `matchmakingType` does not exist, the response will contain an error. 65 | -------------------------------------------------------------------------------- /docs/meet/matchmaking/rankings.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get matchmaking rankings 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/matchmaking/{matchmakingType}/leaderboard?length={length}&offset={offset} 7 | 8 | audience: NadeoLiveServices 9 | 10 | parameters: 11 | path: 12 | - name: matchmakingType 13 | type: integer 14 | description: The ID of the matchmaking type 15 | required: true 16 | query: 17 | - name: length 18 | type: integer 19 | description: The number of ranks to retrieve 20 | required: false 21 | default: 10 22 | max: 100 23 | - name: offset 24 | type: integer 25 | description: The number of ranks to skip 26 | required: false 27 | default: 0 28 | --- 29 | 30 | Gets global matchmaking rankings for the specified type. 31 | 32 | --- 33 | 34 | **Remarks**: 35 | 36 | - The `matchmakingType` parameter is typically one of `2` (Ranked) or `3` (Royal). For a dynamic way of retrieving those IDs see [the matchmaking summary endpoint](/meet/matchmaking/summary). 37 | - This leaderboard doesn't have the same restrictions as the map leaderboard endpoints - you can request any position and will get an accurate rank for each player. 38 | - The `cardinal` field in the response is the total number of players in the ranking. 39 | 40 | --- 41 | 42 | **Example request**: 43 | 44 | ```plain 45 | GET https://meet.trackmania.nadeo.club/api/matchmaking/2/leaderboard?offset=10&length=5 46 | ``` 47 | 48 | **Example response**: 49 | 50 | ```json 51 | { 52 | "matchmakingId": 2, 53 | "cardinal": 1157847, 54 | "results": [ 55 | { 56 | "player": "c0d0d93b-8396-40dd-a928-377c436e8a70", 57 | "rank": 11, 58 | "score": 4339 59 | }, 60 | { 61 | "player": "bb4af693-5190-44c5-8448-d4ec36d95400", 62 | "rank": 12, 63 | "score": 4333 64 | }, 65 | { 66 | "player": "ac935c32-4986-4af7-ac4d-ab4314101bc1", 67 | "rank": 13, 68 | "score": 4312 69 | }, 70 | { 71 | "player": "a8bec23d-e5ba-47d3-8bb7-145b23d9650d", 72 | "rank": 14, 73 | "score": 4281 74 | }, 75 | { 76 | "player": "3ea2b566-7097-4fbf-a91f-68de95adc232", 77 | "rank": 15, 78 | "score": 4271 79 | } 80 | ] 81 | } 82 | ``` 83 | 84 | If the requested `matchmakingType` does not exist, the response will contain an error. 85 | -------------------------------------------------------------------------------- /docs/meet/matchmaking/summary.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get matchmaking IDs 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/official/summary 7 | 8 | audience: NadeoLiveServices 9 | --- 10 | 11 | Gets internal identifiers for the different matchmaking modes. 12 | 13 | --- 14 | 15 | **Example request**: 16 | 17 | ```plain 18 | GET https://meet.trackmania.nadeo.club/api/official/summary 19 | ``` 20 | 21 | **Example response**: 22 | 23 | ```json 24 | { 25 | "ranked3v3Id": 2, 26 | "ranked_3v3_id": 2, 27 | "royalId": 3, 28 | "royal_id": 3, 29 | "superRoyalId": 4, 30 | "super_royal_id": 4 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/meet/super-royal/statistics.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get Super Royal statistics 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/me/super-royal/stats 7 | 8 | audience: NadeoLiveServices 9 | --- 10 | 11 | Gets Super Royal statistics for the current account. 12 | 13 | --- 14 | 15 | **Example request**: 16 | 17 | ```plain 18 | GET https://meet.trackmania.nadeo.club/api/me/super-royal/stats 19 | ``` 20 | 21 | **Example response**: 22 | 23 | ```json 24 | { 25 | "masterWon": 0, 26 | "goldWon": 1, 27 | "silverWon": 2, 28 | "bronzeWon": 5 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/meet/super-royal/status.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get Super Royal status 3 | 4 | url: https://meet.trackmania.nadeo.club 5 | method: GET 6 | route: /api/me/super-royal/current 7 | 8 | audience: NadeoLiveServices 9 | --- 10 | 11 | Gets information about the current Super Royal competition. 12 | 13 | --- 14 | 15 | **Example request**: 16 | 17 | ```plain 18 | GET https://meet.trackmania.nadeo.club/api/me/super-royal/current 19 | ``` 20 | 21 | **Example response**: 22 | 23 | ```json 24 | { 25 | "startsIn": 15318, 26 | "status": "pending", 27 | "matchLiveId": null 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/oauth/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: OAuth 3 | pages: 4 | - summary 5 | - auth 6 | dirs: 7 | - reference 8 | --- 9 | -------------------------------------------------------------------------------- /docs/oauth/reference/accounts/id-to-name.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get account name 3 | 4 | url: https://api.trackmania.com 5 | method: GET 6 | route: /api/display-names?accountId[]={accountId} 7 | 8 | parameters: 9 | query: 10 | - name: accountId 11 | type: string 12 | description: The ID of the account you want to retrieve the name for 13 | required: true 14 | max: 50 account IDs 15 | --- 16 | 17 | Retrieves the account name for a given `accountId`. 18 | 19 | --- 20 | 21 | **Remarks**: 22 | 23 | - To convert more than one ID at a time, you can send an array of values instead of a single value - see the second example below. 24 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 25 | 26 | --- 27 | 28 | **Example request**: 29 | 30 | ```plain 31 | GET https://api.trackmania.com/api/display-names?accountId[]=5b4d42f4-c2de-407d-b367-cbff3fe817bc 32 | ``` 33 | 34 | **Example response**: 35 | 36 | ```json 37 | { 38 | "5b4d42f4-c2de-407d-b367-cbff3fe817bc": "tooInfinite" 39 | } 40 | ``` 41 | 42 | To retrieve more than one name at once, send the `accountId` values as follows: 43 | 44 | ```plain 45 | GET https://api.trackmania.com/api/display-names?accountId[]=5b4d42f4-c2de-407d-b367-cbff3fe817bc&accountId[]=4c803b5a-a344-4d5c-a358-d8f7455d6c85 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/oauth/reference/accounts/name-to-id.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get account ID 3 | 4 | url: https://api.trackmania.com 5 | method: GET 6 | route: /api/display-names/account-ids?displayName[]={accountName} 7 | 8 | parameters: 9 | query: 10 | - name: accountName 11 | type: string 12 | description: The name of the account you want to retrieve the ID for 13 | required: true 14 | --- 15 | 16 | Retrieves the `accountId` for a given account name. 17 | 18 | --- 19 | 20 | **Remarks**: 21 | 22 | - To convert more than one name at a time, you can send an array of values instead of a single value - see the second example below. 23 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 24 | 25 | --- 26 | 27 | **Example request**: 28 | 29 | ```plain 30 | GET https://api.trackmania.com/api/display-names/account-ids?displayName[]=tooInfinite 31 | ``` 32 | 33 | **Example response**: 34 | 35 | ```json 36 | { 37 | "tooInfinite": "5b4d42f4-c2de-407d-b367-cbff3fe817bc" 38 | } 39 | ``` 40 | 41 | To retrieve more than one ID at once, send the `accountName` values as follows: 42 | 43 | ```plain 44 | GET https://api.trackmania.com/api/display-names/account-ids?displayName[]=tooInfinite&displayName[]=Nsgr 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/oauth/reference/accounts/player.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get authorized player 3 | 4 | url: https://api.trackmania.com 5 | method: GET 6 | route: /api/user 7 | --- 8 | 9 | Retrieves the currently authorized player account 10 | 11 | --- 12 | 13 | **Remarks**: 14 | - This endpoint can be used as an additional authentication step after the initial authorization flow. 15 | - This endpoint can not be used with a token obtained from the **Client Credentials** flow, because it has to be associated with a player. 16 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 17 | 18 | --- 19 | 20 | **Example request**: 21 | ```plain 22 | GET https://api.trackmania.com/api/user 23 | ``` 24 | 25 | **Example response**: 26 | ```json 27 | { 28 | "accountId": "5b4d42f4-c2de-407d-b367-cbff3fe817bc", 29 | "displayName": "tooInfinite" 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/oauth/reference/clubs/admin-clubs.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get player's admin clubs 3 | 4 | url: https://api.trackmania.com 5 | method: GET 6 | route: /api/user/clubs/admin 7 | --- 8 | 9 | Retrieves the clubs the authorized player is an admin in. 10 | 11 | --- 12 | 13 | **Remarks**: 14 | - This endpoint requires the `clubs` scope. 15 | - This endpoint can not be used with a token obtained from the **Client Credentials** flow, because it has to be associated with a player. 16 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 17 | 18 | --- 19 | 20 | **Example request**: 21 | ```plain 22 | GET https://api.trackmania.com/api/user/clubs/admin 23 | ``` 24 | 25 | **Example response**: 26 | ```json 27 | { 28 | "clubs": [ 29 | { 30 | "id": 12730, 31 | "name": "TM SCENERY HUB" 32 | } 33 | ] 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/oauth/reference/favorites/add-favorite.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Add favorite map 3 | 4 | url: https://api.trackmania.com 5 | method: POST 6 | route: /api/user/maps/favorite/add 7 | --- 8 | 9 | The request body is a JSON object containing the map's UID: 10 | ```json 11 | { 12 | "uid": "JlxlB7KbrCfhjAf5ld89ByXR987" 13 | } 14 | ``` 15 | 16 | --- 17 | 18 | Adds a map to the player's favorite maps. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - This endpoint requires the `write_favorite` scope. 24 | - This endpoint can not be used with a token obtained from the **Client Credentials** flow, because it has to be associated with a player. 25 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 26 | 27 | --- 28 | 29 | **Example request**: 30 | ```plain 31 | POST https://api.trackmania.com/api/user/maps/favorite/add 32 | ``` 33 | ```json 34 | { 35 | "uid": "JlxlB7KbrCfhjAf5ld89ByXR987" 36 | } 37 | ``` 38 | 39 | **Example response**: 40 | 41 | A successful response has no content and a `204` response code. 42 | -------------------------------------------------------------------------------- /docs/oauth/reference/favorites/favorites.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Get favorite maps 3 | 4 | url: https://api.trackmania.com 5 | method: GET 6 | route: /api/user/maps/favorite?length={length}&offset={offset} 7 | 8 | parameters: 9 | path: 10 | - name: length 11 | type: integer 12 | description: The number of maps to retrieve (10 by default, 100 is the maximum) 13 | required: false 14 | - name: offset 15 | type: integer 16 | description: The number of maps to skip 17 | required: false 18 | --- 19 | 20 | Retrieves the player's favorite maps. 21 | 22 | --- 23 | 24 | **Remarks**: 25 | - This endpoint requires the `read_favorite` scope. 26 | - This endpoint can not be used with a token obtained from the **Client Credentials** flow, because it has to be associated with a player. 27 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 28 | 29 | --- 30 | 31 | **Example request**: 32 | ```plain 33 | GET https://api.trackmania.com/api/user/maps/favorite?length=1&offset=3 34 | ``` 35 | 36 | **Example response**: 37 | ```json 38 | { 39 | "list": [ 40 | { 41 | "uid": "JlxlB7KbrCfhjAf5ld89ByXR987", 42 | "name": "Winter 2022 - 01", 43 | "author": "d2372a08-a8a1-46cb-97fb-23a161d85ad0", 44 | "thumbnailUrl": "https://prod.trackmania.core.nadeo.online/storageObjects/3ddb465d-0357-41c0-9946-394b96836577.jpg" 45 | } 46 | ] 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/oauth/reference/favorites/remove-favorite.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Remove favorite map 3 | 4 | url: https://api.trackmania.com 5 | method: POST 6 | route: /api/user/maps/favorite/remove 7 | --- 8 | 9 | The request body is a JSON object containing the map's UID: 10 | ```json 11 | { 12 | "uid": "JlxlB7KbrCfhjAf5ld89ByXR987" 13 | } 14 | ``` 15 | 16 | --- 17 | 18 | Removes a map from the player's favorite maps. 19 | 20 | --- 21 | 22 | **Remarks**: 23 | - This endpoint requires the `write_favorite` scope. 24 | - This endpoint can not be used with a token obtained from the **Client Credentials** flow, because it has to be associated with a player. 25 | - The access token has to be provided in the `Authorization` header in the format `Bearer `. 26 | 27 | --- 28 | 29 | **Example request**: 30 | ```plain 31 | POST https://api.trackmania.com/api/user/maps/favorite/remove 32 | ``` 33 | ```json 34 | { 35 | "uid": "JlxlB7KbrCfhjAf5ld89ByXR987" 36 | } 37 | ``` 38 | 39 | **Example response**: 40 | 41 | A successful response has no content and a `204` response code. 42 | -------------------------------------------------------------------------------- /docs/oauth/summary.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is an alternative documentation for Trackmania's OAuth implementation - the official one can be found [here](https://doc.trackmania.com/web/web-services/auth/). 4 | 5 | This is **not** related to the game's primary APIs - the OAuth API is completely separate, uses different authentication flows (and tokens) and mostly covers different use cases. 6 | 7 | To get started with the OAuth API, see [the setup instructions](/oauth/auth). 8 | 9 | ## What is OAuth? 10 | 11 | > OAuth (Open Authorization) is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords. 12 | 13 | See [Wikipedia](https://en.wikipedia.org/wiki/OAuth) or [the official OAuth community website](https://oauth.net/) (which also has a useful short video that explains the concept). 14 | 15 | In a broad sense OAuth is meant for authorization as opposed to authentication (it returns an API token, not an identity) - but with an extra request we can extend it to also explicitly authenticate the user. 16 | 17 | There's a ton of useful resources on OAuth out there (note that only the **Authorization Code** and the **Client Credentials** flows are supported by Trackmania) - this guide will just focus on the Trackmania applications. 18 | 19 | ## What is this for? Why would I use it? 20 | 21 | The Trackmania OAuth API can be used for a variety of use cases - typically surrounding verifying a Trackmania player's identity. A couple examples: 22 | 23 | - External websites may want to offer a log-in for players that shows personalized data or lets them perform certain actions that only make sense once their identity has been confirmed. 24 | - [Openplanet](https://openplanet.nl/) plugins might want to verify a player is who they claim they are. This can especially be helpful if the plugin needs to communicate with an external service on behalf of the player. 25 | 26 | Additionally, the API offers an easy way to convert player account IDs into their display names and vice versa - a common use case if your application deals with one of the two types. 27 | 28 | ### Can't I just use an API token for the game APIs? That's unique as well 29 | 30 | The benefit of the dedicated OAuth API is that its token can only really be used for identity verification - normal game API tokens on the other hand can be used to make a variety of different requests, some of which could cause unintended changes in-game or even get the account banned if Nadeo notice suspicious behavior. 31 | 32 | So it's a very bad idea to reuse a player's game API token - especially if you don't even tell the user about the potential ramifications. Even if all your code is public and you can somehow ensure transparently that you don't use the token for anything unexpected, you can never ensure the token doesn't accidentally fall into the wrong hands. 33 | 34 | **Therefore, it's strongly advised not to use a game API token for verifying a player's identity.** 35 | 36 | ## Useful resources 37 | 38 | Below you'll find some resources that can be useful when implementing Trackmania OAuth into your project: 39 | 40 | - [Trackmania Identity Provider for Keycloak](https://github.com/EvoEsports/keycloak-trackmania) 41 | -------------------------------------------------------------------------------- /public/css/Atkinson-Hyperlegible-Bold-102a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/css/Atkinson-Hyperlegible-Bold-102a.woff2 -------------------------------------------------------------------------------- /public/css/Atkinson-Hyperlegible-BoldItalic-102a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/css/Atkinson-Hyperlegible-BoldItalic-102a.woff2 -------------------------------------------------------------------------------- /public/css/Atkinson-Hyperlegible-Italic-102a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/css/Atkinson-Hyperlegible-Italic-102a.woff2 -------------------------------------------------------------------------------- /public/css/Atkinson-Hyperlegible-Regular-102a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/css/Atkinson-Hyperlegible-Regular-102a.woff2 -------------------------------------------------------------------------------- /public/img/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/img/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/img/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/img/android-chrome-256x256.png -------------------------------------------------------------------------------- /public/img/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/img/apple-touch-icon.png -------------------------------------------------------------------------------- /public/img/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/img/favicon-16x16.png -------------------------------------------------------------------------------- /public/img/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/img/favicon-32x32.png -------------------------------------------------------------------------------- /public/img/logo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openplanet-nl/nadeoapi-docs/22be225c9ead6feedd42368c98e17e34db32b1b2/public/img/logo_icon.png -------------------------------------------------------------------------------- /public/img/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 20 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 'Trackmania API documentation - Openplanet', 10 | 'debug' => true, 11 | 'routing' => [ 12 | 'preferRules' => false, 13 | 'rules' => [ 14 | '/^\\/(?[a-z0-9\\-\\/]+)$/' => 'IndexController.Page', 15 | ], 16 | ], 17 | 'cache' => [ 18 | 'class' => 'APCu', 19 | ], 20 | ]); 21 | -------------------------------------------------------------------------------- /public/js/script.js: -------------------------------------------------------------------------------- 1 | const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); 2 | if ($navbarBurgers.length > 0) { 3 | $navbarBurgers.forEach(el => { 4 | el.addEventListener('click', () => { 5 | const target = el.dataset.target; 6 | const $target = document.getElementById(target); 7 | el.classList.toggle('is-active'); 8 | $target.classList.toggle('is-active'); 9 | }); 10 | }); 11 | } 12 | 13 | hljs.highlightAll(); 14 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "icons": [ 4 | { 5 | "src": "/img/android-chrome-192x192.png", 6 | "sizes": "192x192", 7 | "type": "image/png" 8 | }, 9 | { 10 | "src": "/img/android-chrome-256x256.png", 11 | "sizes": "256x256", 12 | "type": "image/png" 13 | } 14 | ], 15 | "theme_color": "#ffffff", 16 | "background_color": "#ffffff", 17 | "display": "standalone" 18 | } 19 | -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker push registry.mrag.nl/openplanet/nadeo-api 3 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import re 5 | import yaml 6 | 7 | def parse_frontmatter(fh): 8 | text = '' 9 | while True: 10 | line = fh.readline() 11 | if not line or line == '---\n': 12 | break 13 | text += line 14 | return yaml.safe_load(text) 15 | 16 | def test_valid_link(link): 17 | if not link.startswith('/'): 18 | raise Exception('Internal link must start with a slash: "' + link + '"') 19 | 20 | path, anchor = re.findall('^/([^#\s]+)?(#.+)?$', link)[0] 21 | 22 | # fall back to root index file if there is no path 23 | if path == '' or path.endswith('/'): 24 | path += 'index' 25 | 26 | if not os.path.exists('docs/' + path) and not os.path.exists('docs/' + path + '.md'): 27 | raise Exception('Internal link goes to a non-existing page: "' + link + '"') 28 | 29 | def test_valid_link_targets(content): 30 | for link in re.findall('\\[.+\\]\\((.+?)\\)', content): 31 | if link.startswith('http://'): 32 | raise Exception('Insecure link on page: "' + link + '"') 33 | elif link.startswith('https://'): 34 | pass # External links are fine 35 | elif link.startswith('#'): 36 | pass # Anchor links are fine 37 | else: 38 | test_valid_link(link) 39 | 40 | def test_valid_frontmatter(path, frontmatter): 41 | if frontmatter == False: 42 | return 43 | 44 | relative_path = os.path.dirname(path) 45 | 46 | if 'pages' in frontmatter: 47 | for page in frontmatter['pages']: 48 | page_path = relative_path + '/' + page + '.md' 49 | if not os.path.exists(page_path): 50 | raise Exception('Page in frontmatter does not exist: "' + page + '" (looking for "' + page_path + '")') 51 | 52 | if 'dirs' in frontmatter: 53 | for dir in frontmatter['dirs']: 54 | dir_path = relative_path + '/' + dir 55 | if not os.path.exists(dir_path): 56 | raise Exception('Directory in frontmatter does not exist: "' + dir + '" (looking for "' + dir_path + '")') 57 | 58 | if 'roots' in frontmatter: 59 | for root in frontmatter['roots']: 60 | root_path = relative_path + '/' + root 61 | if not os.path.exists(root_path): 62 | raise Exception('Root in frontmatter does not exist: "' + root + '" (looking for "' + root_path + '")') 63 | 64 | def test_page(path, frontmatter, content): 65 | print('Page: ' + path) 66 | 67 | test_valid_frontmatter(path, frontmatter) 68 | test_valid_link_targets(content) 69 | 70 | def test_file(path): 71 | line_number = 0 72 | frontmatter = False 73 | content = '' 74 | 75 | fh = open(path, 'r', encoding='utf8') 76 | while True: 77 | line = fh.readline() 78 | if not line: 79 | break 80 | 81 | if line_number == 0 and line == '---\n': 82 | frontmatter = parse_frontmatter(fh) 83 | line_number += 1 84 | continue 85 | 86 | content += line 87 | line_number += 1 88 | 89 | test_page(path, frontmatter, content) 90 | 91 | fh.close() 92 | 93 | def test_dir(path = ''): 94 | with os.scandir('docs/' + path) as it: 95 | for entry in it: 96 | if entry.is_file(): 97 | test_file('docs/' + path + entry.name) 98 | else: 99 | test_dir(path + entry.name + '/') 100 | 101 | test_dir() 102 | print('\nAll tests passed!') 103 | -------------------------------------------------------------------------------- /views/error.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | -------------------------------------------------------------------------------- /views/index/api-param.php: -------------------------------------------------------------------------------- 1 |
  • 2 | {} 3 | () 4 | 5 | 6 | 7 | * 8 | 9 | 10 | 11 |
    12 | 13 | Minimum: 14 | 15 | 16 | 17 | Maximum: 18 | 19 | 20 | 21 | Default: 22 | 23 | 24 |
    25 | 26 |
  • 27 | -------------------------------------------------------------------------------- /views/index/api.php: -------------------------------------------------------------------------------- 1 |

    meta['name']) ?>

    2 | 3 | meta['warning'])) { ?> 4 |
    5 | 6 | meta['warning']) ?> 7 |
    8 | 9 | 10 | meta['danger'])) { ?> 11 |
    12 | 13 | meta['danger']) ?> 14 |
    15 | 16 | 17 | 18 | meta['method']) ?> 24 | getRouteHtml() ?> 25 | 26 | 27 | meta['audience'])) { ?> 28 |
    29 |
    30 |

    Headers:

    31 |
      32 |
    • 33 | Authorization: nadeo_v1 t={token} 34 | An access token for the meta['audience']) ?> audience 35 |
    • 36 |
    37 |
    38 | 39 | 40 | meta['parameters'])) { 42 | $params = $page->meta['parameters']; 43 | 44 | if (isset($params['path'])) { 45 | $params_path = $params['path']; 46 | ?> 47 |
    48 |
    49 |

    Path parameters:

    50 |
      51 | renderPartial('api-param', [ 54 | 'class' => 'warning', 55 | 'item' => $item, 56 | ]); 57 | } 58 | ?> 59 |
    60 |
    61 | 67 |
    68 |
    69 |

    Query parameters:

    70 |
      71 | renderPartial('api-param', [ 74 | 'class' => 'info', 75 | 'item' => $item, 76 | ]); 77 | } 78 | ?> 79 |
    80 |
    81 | 87 |
    88 |
    89 |

    Body parameters:

    90 |
      91 | renderPartial('api-param', [ 94 | 'class' => 'warning', 95 | 'item' => $item, 96 | ]); 97 | } 98 | ?> 99 |
    100 |
    101 | 105 | 106 |
    107 | 108 |
    109 | getHtml() ?> 110 |
    111 | -------------------------------------------------------------------------------- /views/index/page-index.php: -------------------------------------------------------------------------------- 1 |

    2 | 3 | renderPartial('page-list', [ 4 | 'path' => $path, 5 | 'info' => $info, 6 | ]) ?> 7 | -------------------------------------------------------------------------------- /views/index/page-list.php: -------------------------------------------------------------------------------- 1 | '; 5 | echo ''; 6 | echo Nin\Html::encode($page['name']); 7 | echo ''; 8 | if (isset($page['children']) && count($page['children']) > 0) { 9 | echo '
      '; 10 | foreach ($page['children'] as $child) { 11 | renderListItem($path . '/' . $page['path'], $child); 12 | } 13 | echo '
    '; 14 | } 15 | echo ''; 16 | } 17 | ?> 18 | 19 |
    20 |
      21 | 26 |
    27 |
    28 | -------------------------------------------------------------------------------- /views/index/page.php: -------------------------------------------------------------------------------- 1 |
    2 | getHtml() ?> 3 |
    4 | 5 | 6 |
    7 | 8 | renderPartial('page-list', [ 9 | 'path' => $path, 10 | 'info' => $info, 11 | ]) ?> 12 | 13 | -------------------------------------------------------------------------------- /views/layout.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <?= $title ?> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
    28 |
    29 |
    30 |
    31 |

    Service provided by 32 | 33 | 34 | Openplanet 35 | 36 |

    37 |

    - 38 | 39 | Join Discord 40 | 41 | 42 |

    43 |
    44 | 45 |
    46 |

    47 | Contribute on Github 48 | 49 |

    50 |
    51 |
    52 |
    53 |
    54 | 55 | 65 | 66 |
    67 |
    68 |
    69 |
    70 | renderPartial('/menu/menu', [ 71 | 'index' => $this->getPageIndex(), 72 | ]) ?> 73 |
    74 | 75 |
    76 | 94 | 95 | 96 |
    97 |
    98 |
    99 |
    100 | 101 |
    102 |
    103 |

    This documentation is not affiliated with or endorsed by Nadeo or Ubisoft. All relevant trademarks belong to their respective owners.

    104 |

    This is a collaborative project, consider contributing on Github!

    105 |
    106 |
    107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /views/menu/item.php: -------------------------------------------------------------------------------- 1 | 12 |
  • 13 | > 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
      22 | renderPartial('/menu/item', [ 25 | 'path' => $path . $item['path'] . '/', 26 | 'item' => $child, 27 | ]); 28 | } 29 | ?> 30 |
    31 | 32 |
  • 33 | -------------------------------------------------------------------------------- /views/menu/menu.php: -------------------------------------------------------------------------------- 1 | 75 | --------------------------------------------------------------------------------