├── Index.md ├── LiveServices.md ├── Login.md ├── MSR-Akamai.md ├── ProdTrackmania.md ├── README.md ├── TopicIndex.md ├── UbiServices.md ├── UseCases.md └── loginTrackmania.png /Index.md: -------------------------------------------------------------------------------- 1 | # Overall Index 2 | 3 | ## ProdTrackmania 4 | 5 | * [GET /client/config](ProdTrackmania.md#get-clientconfig) 6 | * [PUT /waitingQueue/*some id*](ProdTrackmania.md#put-waitingQueuesome-id) 7 | * [POST /v2/authentication/token/ubiservices](ProdTrackmania.md#post-v2authenticationtokenubiservices) 8 | * [PUT /accounts/*accountId*/presence](ProdTrackmania.md#put-accountsaccountIdpresence) 9 | * [GET /accounts/*accountId*/policies/global/rules](ProdTrackmania.md#get-accountsaccountIdpoliciesglobalrules) 10 | * [GET /accounts/*accountId*/client/config](ProdTrackmania.md#get-accountsaccountIdclientconfig) 11 | * [GET /accounts/*accountId*/client/signature](ProdTrackmania.md#get-accountsaccountIdclientsignature) 12 | * [GET /accounts/*accountId*/encryptedPackage/key](ProdTrackmania.md#get-accountsaccountIdencryptedPackagekey) 13 | * [GET /client/updaters/current](ProdTrackmania.md#get-clientupdaterscurrent) 14 | * [GET /accounts/*accountId*/client/urls](ProdTrackmania.md#get-accountsaccountIdclienturls) 15 | * [GET /accounts/*accountId*/client/plugins](ProdTrackmania.md#get-accountsaccountIdclientplugins) 16 | * [GET /zones](ProdTrackmania.md#get-zones) 17 | * [GET /accounts/*accountId*/zone](ProdTrackmania.md#get-accountsaccountIdzone) 18 | * [POST /v2/authentication/token/nadeoservices](ProdTrackmania.md#post-v2authenticationtokennadeoservices) 19 | * [POST /v2/authentication/token/basic](ProdTrackmania.md#post-v2authenticationtokenbasic) 20 | * [GET /mapRecords](ProdTrackmania.md#get-mapRecords) 21 | * [GET /maps](ProdTrackmania.md#get-maps) 22 | * [GET /trophies/settings](ProdTrackmania.md#get-trophiessettings) 23 | * [GET /seasons/*seasonid*](ProdTrackmania.md#get-seasonsseasonid) 24 | * [HEAD /storageObjects/*someFileName*](ProdTrackmania.md#head-storageObjectssomeFileName) 25 | * [GET /encryptedPackages/versions](ProdTrackmania.md#get-encryptedPackagesversions) 26 | * [POST /mapRecords](ProdTrackmania.md#post-mapRecords) 27 | * [GET /servers/*someId*](ProdTrackmania.md#get-serverssomeId) 28 | * [GET /accounts/*accountId*/trophies/lastYearSummary](ProdTrackmania.md#get-accountsaccountIdtrophieslastYearSummary) 29 | 30 | ## LiveServices 31 | 32 | * [GET /api/token/campaign/official](LiveServices.md#get-apitokencampaignofficial) 33 | * [GET /api/token/campaign/month](LiveServices.md#get-apitokencampaignmonth) 34 | * [GET /api/token/club/campaign](LiveServices.md#get-apitokenclubcampaign) 35 | * [GET /api/token/leaderboard/group/*groupId*/map](LiveServices.md#get-apitokenleaderboardgroupgroupIdmap) 36 | * [GET /api/token/leaderboard/group/*groupId*/](LiveServices.md#get-apitokenleaderboardgroupgroupId) 37 | * [GET /api/token/leaderboard/group/*groupId*/top](LiveServices.md#get-apitokenleaderboardgroupgroupIdtop) 38 | * [GET /api/token/leaderboard/group/*groupId*/map/*mapId*/top](LiveServices.md#get-apitokenleaderboardgroupgroupIdmapmapIdtop) 39 | * [GET /api/token/leaderboard/group/Personal_Best/map/*mapId*/top](LiveServices.md#get-apitokenleaderboardgroupPersonal_BestmapmapIdtop) 40 | * [GET /api/token/leaderboard/group/Personal_Best/map/*mapId*/surround/1/1](LiveServices.md#get-apitokenleaderboardgroupPersonal_BestmapmapIdsurround11) 41 | * [GET /api/token/club/follower/map/*mapId*](LiveServices.md#get-apitokenclubfollowermapmapId) 42 | * [GET /api/token/club/player-vip/map/*mapId*](LiveServices.md#get-apitokenclubplayer-vipmapmapId) 43 | * [GET /api/token/leaderboard/group/*groupId*/map/*mapId*/level](LiveServices.md#get-apitokenleaderboardgroupgroupIdmapmapIdlevel) 44 | * [POST /api/token/leaderboard/trophy/player](LiveServices.md#post-apitokenleaderboardtrophyplayer) 45 | * [GET /api/token/club/room](LiveServices.md#get-apitokenclubroom) 46 | * [GET /api/token/channel/officialhard](LiveServices.md#get-apitokenchannelofficialhard) 47 | * [POST /api/token/channel/officialhard/join](LiveServices.md#post-apitokenchannelofficialhardjoin) 48 | * [GET /api/token/club/mine](LiveServices.md#get-apitokenclubmine) 49 | * [GET /api/token/club/*clubId*/member/*accountId*](LiveServices.md#get-apitokenclubclubIdmemberaccountId) 50 | * [GET /api/token/club/*clubId*/activity](LiveServices.md#get-apitokenclubclubIdactivity) 51 | * [GET /api/token/club/*clubId*/member](LiveServices.md#get-apitokenclubclubIdmember) 52 | * [GET /api/token/club/*clubId*/member/request](LiveServices.md#get-apitokenclubclubIdmemberrequest) 53 | * [GET /api/token/club/*clubId*/room/*activityId(?)*](LiveServices.md#get-apitokenclubclubIdroomactivityId(?)) 54 | * [GET /api/token/club/bucket/skin-upload/all](LiveServices.md#get-apitokenclubbucketskin-uploadall) 55 | * [GET /api/token/map-review/waiting-time](LiveServices.md#get-apitokenmap-reviewwaiting-time) 56 | * [GET /api/token/map-review/connect](LiveServices.md#get-apitokenmap-reviewconnect) 57 | 58 | ## UbiServices 59 | 60 | * [POST /v3/profiles/session](UbiServices.md#post-v3profilessession) 61 | * [GET /v1/applications/86263886-327a-4328-ac69-527f0d20a237/parameters](UbiServices.md#get-v1applications86263886-327a-4328-ac69-527f0d20a237parameters) 62 | * [PUT /v1/profiles/me/populations/data](UbiServices.md#put-v1profilesmepopulationsdata) 63 | * [GET /v1/spaces/*profileId*/parameters](UbiServices.md#get-v1spacesprofileIdparameters) 64 | * [GET /v1/spaces/*profileId*/configs/primarystore](UbiServices.md#get-v1spacesprofileIdconfigsprimarystore) 65 | * [GET v3/profiles](UbiServices.md#get-v3profiles) 66 | 67 | ## Routes msr-public.aws-ubiservices.ubi.com 68 | 69 | * [GET /v4/spaces/*profileId*/configs/events](MSR-Akamai.md#get-v4spacesprofileIdconfigsevents) 70 | * [POST /v3/profiles/me/events](MSR-Akamai.md#post-v3profilesmeevents) 71 | * [GET /club/*clubId*/activity/*nameContent*](MSR-Akamai.md#get-clubclubidactivitynamecontent-exclub3118activity658045f18c059062cfpngupdatetimestamp1595457628png) -------------------------------------------------------------------------------- /LiveServices.md: -------------------------------------------------------------------------------- 1 | # Routes live-services.trackmania.nadeo.live 2 | 3 | Because most of the time the game uses the same headers, the next headers are "general headers", and then in every endpoint I will specify with just a number the headers needed, and that number represent the same number I list the headers in this section 4 | 5 | ***If I put in the JSON Responses \*\* is because I want to hide sensitive information*** 6 | 7 | ## General Headers 8 | 9 | #### 1 10 | 11 | ***I dont think this headers are needed, I can make the same requests without this, so probably you can ignore this headers*** 12 | 13 | * User-Agent: ManiaPlanet/3.3.0 (Win64; rv: 2020-07-23_20_22; context: none; distro: UPLAY) 14 | * Pragma: no-cache 15 | * Cache-Control: no-cache, no-store, must-revalidate 16 | * Accept-Encoding: gzip,deflate 17 | * Accept-Language: en-US,en 18 | * Accept: application/json 19 | * Content-Type: application/json 20 | 21 | #### 2 22 | 23 | Authorization: nadeo_v1 t= 24 | 25 | #### 2.1 26 | 27 | accessToken from Level 1 28 | 29 | #### 2.2 30 | 31 | accessToken from Level 2 - NadeoLiveServices 32 | 33 | #### 2.3 34 | 35 | accessToken from Level 2 - NadeoClubServices 36 | 37 | 38 | ## General Response 39 | 40 | #### 1 41 | 42 | * Transfer-Encoding: chunked 43 | 44 | * Vary: Authorization 45 | 46 | ## GET /api/token/campaign/official 47 | 48 | ### Use: 49 | 50 | Obtain all the seasons, including seasonsIds, groupIds, mapIds, etc. 51 | 52 | ### Request: 53 | 54 | #### Headers: 55 | 56 | *General Headers 1 and 2.2* 57 | 58 | #### Params: 59 | 60 | * offset=*number, example: 0* 61 | * length=*number, example: 1* 62 | 63 | ### Response: 64 | 65 | #### Headers: 66 | 67 | *General Response 1* 68 | 69 | #### Body: 70 | 71 | * ```json 72 | {"campaignList":[{"id":130,"seasonUid":"3987d489-03ae-4645-9903-8f7679c3a418","name":"Summer 2020","color":"","useCase":0,"clubId":null,"leaderboardGroupUid":"3987d489-03ae-4645-9903-8f7679c3a418","publicationTimestamp":1592932080,"publishedDate":1592932080,"year":-1,"week":-1,"day":-1,"monthYear":-1,"month":-1,"monthDay":-1,"published":true,"playlist":[{"id":1028,"position":0,"mapUid":"XJ_JEjWGoAexDWe8qfaOjEcq5l8"}, ......], "latestSeasons":[{"uid":"3987d489-03ae-4645-9903-8f7679c3a418","name":"Summer 2020 #1","startTimestamp":1592932080,"startDate":1592932080,"endTimestamp":null,"endDate":null,"relativeStart":-2682526,"relativeEnd":null,"campaignId":130,"active":true}], ,"categories":[{"position":0,"length":1,"name":"0"},{"position":1,"length":1,"name":"1"},{"position":2,"length":1,"name":"2"},{"position":3,"length":1,"name":"3"},{"position":4,"length":1,"name":"4"}],"media":{"buttonBackgroundUrl":"","buttonForegroundUrl":"","popUpBackgroundUrl":"","popUpImageUrl":"","liveButtonBackgroundUrl":""}}],"itemCount":1} 73 | ``` 74 | 75 | * campaignList, with each object representing a campaing with a id, seasonUid, name, color, useCase, clubId, leaderboardGroupUid, publicationTimestamp, publishedDate, year, week, day, monthYear, month, monthDay, published, playlist that contains the maps, each one with an Id, position and mapUid, and then latestSeason with Uid, name, startTimeStamp, startSate, endTimeStamp, endDate, relativeStart, relativeEnd, campaignId, active(boolean), and then categories with objects containing position, length, name, and then media with buttonBackgroundUrl, buttonForegroundUrl, popUpBackgroundUrl, popUpImageUrl, liveButtonBackgroundUrl, and then finally with a itemCount 76 | 77 | ## GET /api/token/campaign/month 78 | 79 | ### Use: 80 | 81 | Obtain all the track of the days, with their respective mapUid and seasonUid 82 | 83 | ### Request: 84 | 85 | #### Headers: 86 | 87 | *General Headers 1 and 2.2* 88 | 89 | #### Params: 90 | 91 | * offset=*number, example: 0* 92 | * length=*number, example: 1* 93 | 94 | ### Response: 95 | 96 | #### Headers: 97 | 98 | *General Response 1* 99 | 100 | #### Body: 101 | 102 | * ```json 103 | {"monthList":[{"year":2020,"month":7,"lastDay":31,"days":[{"campaignId":173,"mapUid":"g7l2eO_x9z4HWGGYj8dVBCDSTEg","day":2,"monthDay":1,"seasonUid":"33181f18-1b3d-4ed4-94b3-92e4c809e1e9","relativeStart":-2002606,"relativeEnd":-1905406,"leaderboardGroup":null}, ......], "media":{"buttonBackgroundUrl":"","buttonForegroundUrl":"","popUpBackgroundUrl":"","popUpImageUrl":"","liveButtonBackgroundUrl":""}}],"itemCount":1} 104 | ``` 105 | 106 | * monthlist, each object inside this array represents a month of track of the day, each one with a array representing the maps, each one with campaignId, mapUid, day (day of the week), monthDay, seasonUid(each track have his own season), relativeStart, relativeEnd (to check how many time the track started and how many time his left to be end, in this case both are negative, so the track is already closed), leaderboardGroup. Then, after the array of maps comes the media object with buttonBackgroundUrl, buttonForegroundUrl, popUpBackgroundUrl, popUpImageUrl, liveButtonBackgroundUrl. Then, after this all, the last value is itemCount, maybe representing the number of months that are in the JSON 107 | 108 | ## GET /api/token/club/campaign 109 | 110 | ### Use: 111 | 112 | List clubs campaigns (used when we are in Solo Screen and looking for Club Campaigns) 113 | 114 | ### Request: 115 | 116 | #### Headers: 117 | 118 | *General Headers 1 and 2.2* 119 | 120 | #### Params: 121 | 122 | * offset=*number, example: 0* 123 | * length=*number, example: 75* 124 | * sort=popularity (*maybe other type of sort available idk*) 125 | * order=DESC (*maybe other type of order available idk*) 126 | 127 | ### Response 128 | 129 | #### Headers: 130 | 131 | *General Response 1* 132 | 133 | #### Body: 134 | 135 | * ```json 136 | {"clubCampaignList":[{"clubId":10,"clubIconUrl":"http:\/\/trackmania-prod-nls-file-store-s3.mdc.akamaized.net\/club\/10\/logo\/5eda9e8eba5af.png?updateTimestamp=1591385745.png","clubDecalUrl":"","campaignId":25,"publicationTimestamp":1591434456,"publishedOn":1591434456,"creationTimestamp":1591434449,"activityId":51,"mediaUrl":"http:\/\/trackmania-prod-nls-file-store-s3.mdc.akamaized.net\/club\/10\/activity\/51\/5edb5cd1ed2e1.png?updateTimestamp=1591434454.png","name":"MrLag\u0027s Collection","campaign":{"id":25,"seasonUid":"NLS-mKwyfRyFgiEMJk7Z4d4J7M4VGQ0rRgSOgrk","name":"MrLag\u0027s Collection","color":"","useCase":2,"clubId":10,"leaderboardGroupUid":"NLS-mKwyfRyFgiEMJk7Z4d4J7M4VGQ0rRgSOgrk","publicationTimestamp":1591434456,"publishedDate":1591434456,"year":-1,"week":-1,"day":-1,"monthYear":-1,"month":-1,"monthDay":-1,"published":true,"playlist":[{"id":313,"position":0,"mapUid":"TC7VeIu0YlBPL28pQEVCIB4U3U7"},{"id":314,"position":1,"mapUid":"cauJGEKRavl8OCFq4Bn7zSR6s_f"},{"id":328,"position":2,"mapUid":"XHQXucIBMhpEtF5vzsfuZAC46bg"},{"id":331,"position":3,"mapUid":"g7l2eO_x9z4HWGGYj8dVBCDSTEg"},{"id":409,"position":4,"mapUid":"klhcYiu6u7fHh1mVbniODsNsE5k"},{"id":628,"position":5,"mapUid":"oL9m6YV0WvBJxrXaxS5CGsmYaO9"},{"id":783,"position":6,"mapUid":"zfanSjNNWvSsBUktpFL5VdEMOYh"},{"id":785,"position":7,"mapUid":"aFQ5VqxIzVF0cvvpyVm0NcDn6H3"},{"id":819,"position":8,"mapUid":"n0Sk7NEXWpImPRJj01sAQ_DJO0c"},{"id":832,"position":9,"mapUid":"QAIa5QzuymQu2Bm0ivsHnLq2150"},{"id":1055,"position":10,"mapUid":"YoMVhGI13Q1TeAsPAqkzbi20tn9"},{"id":1161,"position":11,"mapUid":"DR9ERWb19R9QEwb10GrHCtmj0il"},{"id":1162,"position":12,"mapUid":"ExPmQDTImDYrHypihjmN7JhvBV5"},{"id":1163,"position":13,"mapUid":"19EACHLJwIpqxv1l7EneRG4BLJl"},{"id":1330,"position":14,"mapUid":"OhpuXkzfkjChnc35TJRG5AZEMCm"},{"id":5124,"position":15,"mapUid":"gasy2RLKMS7l8BzvZorvWGBXm34"},{"id":7847,"position":16,"mapUid":"tX5RQBdmiVvlinPp9BJ62cpV7P4"}],"latestSeasons":[{"uid":"NLS-mKwyfRyFgiEMJk7Z4d4J7M4VGQ0rRgSOgrk","name":"MrLag\u0027s Collection #1","startTimestamp":1595599135,"startDate":1595599135,"endTimestamp":null,"endDate":null,"relativeStart":-15446,"relativeEnd":null,"campaignId":25,"active":true}],"categories":[{"position":0,"length":5,"name":"MrLag\u0027s Collection"}],"media":{"buttonBackgroundUrl":"","buttonForegroundUrl":"","popUpBackgroundUrl":"","popUpImageUrl":"","liveButtonBackgroundUrl":""}},"popularityLevel":3}, ......], "maxPage":15, "itemCount":1098 137 | ``` 138 | 139 | * clubCampaignList, with each object having a clubId, clubIconUrl, clubDecalUrl, campaignId, publicationTimeStamp, publishedOn, creationTimestamp, activityId, mediaUrl, name, campaign with a id, seasonUid, name, color, useCase, clubId, leaderboardGroupUid, publicationTimestamp, publishedDate, year, week, day, monthYear, month, monthDay, published, playlist that contains the maps, each one with an Id, position and mapUid, and then latestSeason with Uid, name, startTimeStamp, startSate, endTimeStamp, endDate, relativeStart, relativeEnd, campaignId, active(boolean), and then categories with objects containing position, length, name, and then media with buttonBackgroundUrl, buttonForegroundUrl, popUpBackgroundUrl, popUpImageUrl, liveButtonBackgroundUrl, and then popularityLevel. After all the objects of the clubs, we have a maxPage and a itemCount 140 | 141 | ## GET /api/token/leaderboard/group/*groupId*/map 142 | 143 | ### Use: 144 | 145 | Obtain your position in the leaderboard for a specific group and a list of map 146 | 147 | ### Request: 148 | 149 | #### Headers: 150 | 151 | *General Headers 1 and 2.2* 152 | 153 | #### Params: 154 | 155 | * scores%*mapId*=*your time record (ex: 00:19:254 is 19254)* **AND THIS IS A LIST** 156 | 157 | ### Response: 158 | 159 | #### Headers: 160 | 161 | *General Response 1* 162 | 163 | #### Body: 164 | 165 | * ```json 166 | {"0fJFNOS8ZzfDA6fJQrr5JU0JIom":{"groupUid":"3987d489-03ae-4645-9903-8f7679c3a418","mapUid":"0fJFNOS8ZzfDA6fJQrr5JU0JIom","score":48745,"zones":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","ranking":{"position":1995,"length":0}},{"zoneId":"301e2106-7e13-11e8-8060-e284abfd2bc4","zoneName":"Europe","ranking":{"position":1811,"length":0}}, ***...***} 167 | ``` 168 | 169 | * An JSON object, with each atribute inside him representing a mapUid that contains the groupUid, mapUid, score (our record, and the one passed by query parameter), and then zones array with objects having zoneId, zoneName, position and length 170 | 171 | ## GET /api/token/leaderboard/group/*groupId*/map 172 | 173 | ### Use: 174 | 175 | Returns your record in everymap of that group, and your position in each zone 176 | 177 | ### Request: 178 | 179 | #### Headers: 180 | 181 | *General Headers 1 and 2.2* 182 | 183 | ### Response: 184 | 185 | #### Headers: 186 | 187 | *General Response 1* 188 | 189 | #### Body: 190 | 191 | * ```json 192 | {"5w5yGqmOIKOpUGxAEhonlGP04W4":{"groupUid":"NLS-jVyu9CVZvWCVNxudXYvwS92FRdOEcOPysOK","mapUid":"5w5yGqmOIKOpUGxAEhonlGP04W4","score":57223,"zones":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","ranking":{"position":1201,"length":0}},{"zoneId":"301e2106-7e13-11e8-8060-e284abfd2bc4","zoneName":"Europe","ranking":{"position":1093,"length":0}}, ......]}, ......} 193 | ``` 194 | 195 | * JSON object with each attribute representing the mapId of each track on that group, and each object have a groupUid, mapUid, score (your score), zones array with each object having zoneId, zoneName, ranking having position and length 196 | 197 | ## GET /api/token/leaderboard/group/*groupId* 198 | 199 | ### Use: 200 | 201 | Get your position in a group (ex: overall ranking on Summer Season 2020 in world, country, etc.) 202 | 203 | ### Request: 204 | 205 | #### Headers: 206 | 207 | *General Headers 1 and 2.2* 208 | 209 | ### Response: 210 | 211 | #### Headers: 212 | 213 | *General Response 1* 214 | 215 | #### Body: 216 | 217 | * ```json 218 | {"groupUid":"3987d489-03ae-4645-9903-8f7679c3a418","sp":"17284","zones":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","ranking":{"position":1553,"length":0}}, ......} 219 | ``` 220 | 221 | * groupUid, sp, array of zones with zoneId, zoneName, ranking having position and length 222 | 223 | ## GET /api/token/leaderboard/group/*groupId*/top 224 | 225 | ### Use: 226 | 227 | Get the top leaders on a group (ex: top rankings on Summer Season 2020 in world, country, etc.) 228 | 229 | ### Request: 230 | 231 | #### Headers: 232 | 233 | *General Headers 1 and 2.2* 234 | 235 | ### Response: 236 | 237 | #### Headers: 238 | 239 | *General Response 1* 240 | 241 | #### Body: 242 | 243 | * ```json 244 | {"groupUid":"3987d489-03ae-4645-9903-8f7679c3a418","tops":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","top":[{"accountId":"*accountId*","zoneId":"30207cd0-7e13-11e8-8060-e284abfd2bc4","zoneName":"Japan","position":1,"sp":"356215"}, ***...***], ***...***]} 245 | ``` 246 | 247 | * groupUid, tops array with objects having zoneId, zoneName and top array containing objects having accountId, zoneId, zoneName, position and sp 248 | 249 | ## GET /api/token/leaderboard/group/*groupId*/map/*mapId*/top 250 | 251 | ### Use: 252 | 253 | Obtain the top leaders on a specific map (i dont think the query param score is being used, although they used that way...) 254 | 255 | ### Request: 256 | 257 | #### Headers: 258 | 259 | *General Headers 1 and 2.2* 260 | 261 | #### Params: 262 | 263 | * score=*your time record (ex: 00:19:254 is 19254)* 264 | 265 | ### Response: 266 | 267 | #### Headers: 268 | 269 | *General Response 1* 270 | 271 | #### Body: 272 | 273 | * ```json 274 | {"groupUid":"3987d489-03ae-4645-9903-8f7679c3a418","mapUid":"XJ_JEjWGoAexDWe8qfaOjEcq5l8","tops":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","top":[{"accountId":"*accountId*","zoneId":"30229617-7e13-11e8-8060-e284abfd2bc4","zoneName":"Vaud","position":1,"score":19454}, ***...***], ***...***]} 275 | ``` 276 | 277 | * An JSON object with groupUid, mapUid and tops, containing objects for each zone of yours with zoneId, zoneName and top array with objects having accountId, zoneId, zoneName, position and score 278 | 279 | ## GET /api/token/leaderboard/group/Personal_Best/map/*mapId*/top 280 | 281 | ### Use: 282 | 283 | Get the top leaders of a map, with no restriction of a group like the others endpoints 284 | 285 | ### Request: 286 | 287 | #### Headers: 288 | 289 | *General Headers 1 and 2.2* 290 | 291 | ### Response: 292 | 293 | #### Headers: 294 | 295 | *General Response 1* 296 | 297 | #### Body: 298 | 299 | * ```json 300 | {"groupUid":"Personal_Best","mapUid":"XJ_JEjWGoAexDWe8qfaOjEcq5l8","tops":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","top":[{"accountId":"*accountId*","zoneId":"30229617-7e13-11e8-8060-e284abfd2bc4","zoneName":"Vaud","position":1,"score":19454}, ***...***], ***...***]} 301 | ``` 302 | 303 | * An JSON object with groupUid, mapUid and tops, containing objects for each zone of yours with zoneId, zoneName and top array with objects having accountId, zoneId, zoneName, position and score 304 | 305 | ## GET /api/token/leaderboard/group/Personal_Best/map/*mapId*/surround/1/1 306 | 307 | ### Use: 308 | 309 | Get the surrounding leaders around your score on a map, with no restriction of a group like the others endpoints (this one is used in that little leaderboard in game) 310 | 311 | ### Request: 312 | 313 | #### Headers: 314 | 315 | *General Headers 1 and 2.2* 316 | 317 | ### Response: 318 | 319 | #### Headers: 320 | 321 | *General Response 1* 322 | 323 | #### Body: 324 | 325 | * ```json 326 | {"groupUid":"Personal_Best","mapUid":"XJ_JEjWGoAexDWe8qfaOjEcq5l8","tops":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","top":[{"accountId":"*accountId*","zoneId":"301fa93b-7e13-11e8-8060-e284abfd2bc4","zoneName":"Nord","position":1162,"score":19928} 327 | ``` 328 | 329 | * An JSON object with groupUid, mapUid and tops, containing objects for each zone of yours with zoneId, zoneName and top array with objects having accountId, zoneId, zoneName, position and score 330 | 331 | ## GET /api/token/club/follower/map/*mapId* 332 | 333 | ### Use: 334 | 335 | ***Idk*** 336 | 337 | ### Request: 338 | 339 | #### Headers: 340 | 341 | *General Headers 1 and 2.2* 342 | 343 | #### Params: 344 | 345 | * seasonId=*seasonUid* 346 | 347 | ### Response: 348 | 349 | #### Headers: 350 | 351 | *General Response 1* 352 | 353 | #### Body: 354 | 355 | * ```json 356 | {"accountIdList":[]} 357 | ``` 358 | 359 | ## GET /api/token/club/player-vip/map/*mapId* 360 | 361 | ### Use: 362 | 363 | ***Idk*** 364 | 365 | ### Request: 366 | 367 | #### Headers: 368 | 369 | *General Headers 1 and 2.2* 370 | 371 | #### Params: 372 | 373 | * seasonId=*seasonUid* 374 | 375 | ### Response: 376 | 377 | #### Headers: 378 | 379 | *General Response 1* 380 | 381 | #### Body: 382 | 383 | * ```json 384 | {"accountIdList":[]} 385 | ``` 386 | 387 | ## GET /api/token/leaderboard/group/*groupId*/map/*mapId*/level 388 | 389 | ### Use: 390 | 391 | This one seems specific to some zone, I'm not 100% sure where is being used 392 | 393 | ### Request: 394 | 395 | #### Headers: 396 | 397 | *General Headers 1 and 2.2* 398 | 399 | #### Params: 400 | 401 | * score=*your record* 402 | 403 | ### Response: 404 | 405 | #### Headers: 406 | 407 | *General Response 1* 408 | 409 | #### Body: 410 | 411 | * ```json 412 | {"groupUid":"3987d489-03ae-4645-9903-8f7679c3a418","mapUid":"XJ_JEjWGoAexDWe8qfaOjEcq5l8","levels":[{"zoneId":"*zoneId*","zoneName":"*zoneName*","level":[{"accountId":"*accountId*","zoneId":"*zoneId*","zoneName":"*zoneName*","position":14,"score":19908}, ***...***], ***...***]} 413 | ``` 414 | 415 | ## POST /api/token/leaderboard/trophy/player 416 | 417 | ### Use: 418 | 419 | *I think is to obtain the trophys and their position from a list of players passed on the body of the request* 420 | 421 | ### Request: 422 | 423 | #### Headers: 424 | 425 | *General Headers 1 and 2.2* 426 | 427 | * Accept: application/json 428 | * Content-Type: application/json 429 | * Content-Length: 430 | 431 | #### Body: 432 | 433 | * ```json 434 | {"listPlayer":[{"accountId":"*accountId*"}]} 435 | ``` 436 | 437 | ### Response: 438 | 439 | #### Headers: 440 | 441 | *General Response 1* 442 | 443 | #### Body: 444 | 445 | * ```json 446 | {"rankings":[{"countPoint":75638,"accountId":"*accountId*","echelon":5,"zones":[{"zoneId":"301e1b69-7e13-11e8-8060-e284abfd2bc4","zoneName":"World","ranking":{"position":4122,"length":0}}, ***...***]}], "length": 0} 447 | ``` 448 | 449 | * ranking with countPoint, acountId, echelon and zones array with each object having zoneId, zoneName and ranking having position and length 450 | 451 | ## GET /api/token/club/room 452 | 453 | ### Use: 454 | 455 | This is used to obtain the clubs in the Live section of the game 456 | 457 | ### Request: 458 | 459 | #### Headers: 460 | 461 | *General Headers 1 and 2.2* 462 | 463 | * offset=*number, example: 0* 464 | * length=*number, example: 75* 465 | * sort=popularity (*maybe other type of sort available idk*) 466 | * order=DESC (*maybe other type of order available idk*) 467 | 468 | ### Response: 469 | 470 | #### Headers: 471 | 472 | *General Response 1* 473 | 474 | #### Body: 475 | 476 | * ```json 477 | {"clubRoomList":[{"id":283,"clubId":97,"nadeo":true,"roomId":50,"campaignId":null,"playerServerLogin":null,"activityId":283,"mediaUrl":"http:\/\/trackmania-prod-nls-file-store-s3.mdc.akamaized.net\/club\/97\/activity\/283\/5f0866a0545bf.png?updateTimestamp=1594386082.png","name":"Tona\u0027s maps","room":{"id":50,"name":"Tona\u0027s maps","region":null,"serverAccountId":"","maxPlayers":60,"playerCount":393,"maps":["sIYZ2whAcmFytSVRZWPJkByjPP8","gL7NrGjG0GC91nJazHyGwPb_Iok","hg__4dAM5CN1sUxajb9L95olDG1","sZLy_bJbge06NkOTslD9x3Jfq90","HA1BTE5m4y8bsE4T_b0tYcWEwTd","rtzP7y8EgR8jY4MJ0LpK13nALR2","rbWSXxqnEhLecjctuUd_Ebw8G7m","tXQ4XA1DTe7HF5o571sC0oZJ8Ti","6I9T69k86vRcWr4ih4sqSvjQFb3","oBqrQ2BmIMOgrNmbrQSwKdCwBL3"],"script":"TrackMania\/TM_TimeAttack_Online.Script.txt","scriptSettings":{"S_ForceLapsNb":{"key":"S_ForceLapsNb","value":"-1","type":"integer"},"S_DecoImageUrl_Screen16x9":{"key":"S_DecoImageUrl_Screen16x9","value":"http:\/\/trackmania-prod-nls-file-store-s3.mdc.akamaized.net\/club\/97\/screen_16x9\/5efdfb06b545d.dds?updateTimestamp=1593703174.dds","type":"text"}}},"popularityLevel":3,"creationTimestamp":1592242462}, ***...***], "maxPage":86, "itemCount":6397} 478 | ``` 479 | 480 | * clubRoomList with objects having id, clubId, nadeo, roomId, plaerServerLogin, activityId, mediaUrl, name, room having id, name, region, serverAccountId, maxPlayers, playerCount, maps array with strings of mapUids, script, scriptSettings having a S_ForceLapsNb object with key, value and type, and S_DecoImageUrl_Screen16x9 with key, value and type. Then have a popularityLevel and creationTimestamp 481 | 482 | ## GET /api/token/channel/officialhard 483 | 484 | ### Use: 485 | 486 | I think this is specific for the arcade button, where he obtains the information about the current room and the next room 487 | 488 | ### Request: 489 | 490 | #### Headers: 491 | 492 | *General Headers 1 and 2.2* 493 | 494 | ### Response: 495 | 496 | #### Headers: 497 | 498 | *General Response 1* 499 | 500 | #### Body: 501 | 502 | * ```json 503 | {"uid":"officialhard","name":"Official","playerCount":737,"currentTimeSlot":{"startTimestamp":1595613600,"endTimestamp":1595617200,"name":"Summer 2020","maps":["XJ_JEjWGoAexDWe8qfaOjEcq5l8","zFK9sy3nRLa6FGSpuk_gw0cHLv7","xfRvyL9ByoJoPhlAvcNzbc4xD88","8rWFH6JI2N1UuHeaS9dmMkTojS","eWR2OWAaiqQOISa_0roXlpsnQLl","NlKBKke_lk9hwhoEMb6rBQrsWC5","OG0yFZ4bA1iiybF7n4gaZkFO6m9","iWUvrk1X45PaUmKv6HUDak4W6V2","5weePaThiuxiK4mSHOCokBV6bTg","oTGP3jwCiubHBM6KtuR_aCtGWZi","gMsrsG59cdouiAoahyk7wOaPPC3","EY3IfWHWGUtreJzWmAWp00ZT6z2","1MPMjPNGKW_U2Aa1RGyfPDnJVhd","uQrUHGT16AptHdxkUKL3MWuh0Gm","159XBIpjid7Wh4mjIRQ6wazyme4","8JfhDBlUSjG2qf9hqssAJupE0rc","4dRIXY5T5CMh6LPcL88l0gEpBkl","oSqyiU8CN8A4KnYRsqgcIOshYl2","VjBmIAFe_vihp4dA6gXyxauMh_1","bTxEqrds5pszV3PZTdK57AnYWfd","tHdTCbauyKWB_ft2NVRznkCE4rk","dAUOBz9H2iKzyo8HURb3Ce3cwT9","FcNO1D7hn9nLuCrjqSA5_7slkR1","0fJFNOS8ZzfDA6fJQrr5JU0JIom","2katsDjZmPOeQYE94jkbnSoJA64"],"currentMap":"iWUvrk1X45PaUmKv6HUDak4W6V2","relativeStart":-1235,"relativeEnd":2365,"mediaUrl":""},"nextTimeSlot":{"startTimestamp":1595617200,"endTimestamp":1595620800,"name":"Summer 2020","maps":["XJ_JEjWGoAexDWe8qfaOjEcq5l8","zFK9sy3nRLa6FGSpuk_gw0cHLv7","xfRvyL9ByoJoPhlAvcNzbc4xD88","8rWFH6JI2N1UuHeaS9dmMkTojS","eWR2OWAaiqQOISa_0roXlpsnQLl","NlKBKke_lk9hwhoEMb6rBQrsWC5","OG0yFZ4bA1iiybF7n4gaZkFO6m9","iWUvrk1X45PaUmKv6HUDak4W6V2","5weePaThiuxiK4mSHOCokBV6bTg","oTGP3jwCiubHBM6KtuR_aCtGWZi","gMsrsG59cdouiAoahyk7wOaPPC3","EY3IfWHWGUtreJzWmAWp00ZT6z2","1MPMjPNGKW_U2Aa1RGyfPDnJVhd","uQrUHGT16AptHdxkUKL3MWuh0Gm","159XBIpjid7Wh4mjIRQ6wazyme4","8JfhDBlUSjG2qf9hqssAJupE0rc","4dRIXY5T5CMh6LPcL88l0gEpBkl","oSqyiU8CN8A4KnYRsqgcIOshYl2","VjBmIAFe_vihp4dA6gXyxauMh_1","bTxEqrds5pszV3PZTdK57AnYWfd","tHdTCbauyKWB_ft2NVRznkCE4rk","dAUOBz9H2iKzyo8HURb3Ce3cwT9","FcNO1D7hn9nLuCrjqSA5_7slkR1","0fJFNOS8ZzfDA6fJQrr5JU0JIom","2katsDjZmPOeQYE94jkbnSoJA64"],"currentMap":"iWUvrk1X45PaUmKv6HUDak4W6V2","relativeStart":2365,"relativeEnd":5965,"mediaUrl":""}} 504 | ``` 505 | 506 | * JSON having uid, name, playerCount, currentTimeSlot with startTimestamp, endTimestamp, name, array of mapsUids, currentMap, relativeStart, relativeEnd, mediaUrl, and then nextTimeSlot with same sctructure as currentTimeSlot 507 | 508 | ## POST /api/token/channel/officialhard/join 509 | 510 | ### Use: 511 | 512 | Obtain the address the game uses internally to open a connection to a server, this one specific for the arcade button (i think) 513 | 514 | ### Request: 515 | 516 | #### Headers: 517 | 518 | *General Headers 1 and 2.2* 519 | 520 | ### Response: 521 | 522 | #### Headers: 523 | 524 | *General Response 1* 525 | 526 | #### Body: 527 | 528 | * ```json 529 | {"joinLink":"#qjoin=ev747VaUQhyVop_S9krD2A"} 530 | ``` 531 | 532 | * JoinLink for the game to execute 533 | 534 | ## GET /api/token/club/mine 535 | 536 | ### Use: 537 | 538 | List all the clubs in the club section 539 | 540 | ### Request: 541 | 542 | #### Headers: 543 | 544 | *General Headers 1 and 2.2* 545 | 546 | #### Params: 547 | 548 | * offset=*number, example: 0* 549 | * length=*number, example: 90* 550 | 551 | ### Response: 552 | 553 | #### Headers: 554 | 555 | *General Response 1* 556 | 557 | #### Body: 558 | 559 | * ```json 560 | {"clubList":[],"maxPage":0,"clubCount":0} 561 | ``` 562 | 563 | * clubList, and maxPage and clubCount (probably empty cause I dont have club access, **TODO**) 564 | 565 | ## GET /api/token/club/*clubId*/member/*accountId* 566 | 567 | ### Use: 568 | 569 | I think this is used to obtain specific information about a member (the accontId not necessary have to be in the club, is just a request to know, I say this because he send a request with my ID, but I dont have club access so...) 570 | 571 | ### Request: 572 | 573 | #### Headers: 574 | 575 | *General Headers 1 and 2.2* 576 | 577 | ### Response: 578 | 579 | #### Headers: 580 | 581 | *General Response 1* 582 | 583 | #### Body: 584 | 585 | * ```json 586 | {"accountId":"*accountId*","clubId":54,"role":"","creationTimestamp":1595614972,"creationDate":1595614972,"vip":false} 587 | ``` 588 | 589 | * accountId, clubId, role, creationTimestamp, creationDate, vip 590 | 591 | ## GET /api/token/club/*clubId*/activity 592 | 593 | ### Use: 594 | 595 | ***Idk what is activity of a club, maybe is everything about a club (skins, servers, campagins, etc.)?*** 596 | 597 | ### Request: 598 | 599 | #### Headers: 600 | 601 | *General Headers 1 and 2.2* 602 | 603 | #### Params: 604 | 605 | * offset=*number, example: 0* 606 | * length=*number, example: 75* 607 | * active=*number, example: 1, probably only valid values are 0 and 1, as they represent a boolean value* 608 | 609 | ### Response: 610 | 611 | #### Headers: 612 | 613 | *General Response 1* 614 | 615 | #### Body: 616 | 617 | * ```json 618 | {"activityList":[{"id":41928,"name":"Trackmania Cup 2020","activityType":"competition","activityId":41928,"targetActivityId":41928,"campaignId":0,"position":10,"public":true,"active":true,"mediaUrl":"","externalId":1}, ***...***], "maxPage":1, "itemCount":10} 619 | ``` 620 | 621 | * activityList array with objects having id, name, activityType, targetActivityId, campaignId, position, public, active, mediaUrl, externalId, and then maxPage and itemCount 622 | 623 | ## GET /api/token/club/*clubId*/member 624 | 625 | ### Use: 626 | 627 | Obtain all the information about the members of a club 628 | 629 | ### Request: 630 | 631 | #### Headers: 632 | 633 | *General Headers 1 and 2.2* 634 | 635 | #### Params: 636 | 637 | * offset=*number, example: 0* 638 | * length=*number, example: 27* 639 | 640 | ### Response: 641 | 642 | #### Headers: 643 | 644 | *General Response 1* 645 | 646 | #### Body: 647 | 648 | * ```json 649 | {"clubMemberList":[{"accountId":"*accountId*","role":"Creator","creationTimestamp":1592054772,"creationDate":1592054772,"vip":true}, ***...***], "maxPage":595, "itemCount":16055} 650 | ``` 651 | 652 | * clubMemberList array with objects having accountId, role(Creator, Admin or Member), creationTimeStamp, creationDate, vip(boolean), and then maxPage and itemCount 653 | 654 | ## GET /api/token/club/*clubId*/member/request 655 | 656 | ### Use: 657 | 658 | A request to check if this user (with the token) can enter the club **I dont have club access so the response is almost empty** 659 | 660 | ### Request: 661 | 662 | #### Headers: 663 | 664 | *General Headers 1 and 2.2* 665 | 666 | #### Params: 667 | 668 | * offset=*number, example: 0* 669 | * length=*number, example: 27* 670 | 671 | ### Response: 672 | 673 | #### Headers: 674 | 675 | *General Response 1* 676 | 677 | #### Body: 678 | 679 | * ```json 680 | {"clubMemberList":[],"maxPage":0,"itemCount":0} 681 | ``` 682 | 683 | ## GET /api/token/club/*clubId*/room/*activityId(?)* 684 | 685 | ### Use: 686 | 687 | ***Idk, I'm not even sure if the id after the room is the activityId or the roomId*** 688 | 689 | ### Request: 690 | 691 | #### Headers: 692 | 693 | *General Headers 1 and 2.2* 694 | 695 | ### Response: 696 | 697 | #### Headers: 698 | 699 | *General Response 1* 700 | 701 | #### Body: 702 | 703 | * ```json 704 | {"id":766,"clubId":41,"nadeo":false,"roomId":null,"campaignId":null,"playerServerLogin":"evofsb","activityId":766,"mediaUrl":"http:\/\/trackmania-prod-nls-file-store-s3.mdc.akamaized.net\/club\/41\/activity\/766\/5efc7da3105a9.png?updateTimestamp=1593605542.png","name":"$sEvo $07AFullspeed Beg","room":{"id":null,"name":"","region":null,"serverAccountId":"bc251924-d267-4702-b526-9ed4b950d729","maxPlayers":0,"playerCount":87,"maps":[],"script":"","scriptSettings":[],"serverInfo":null},"popularityLevel":1,"creationTimestamp":1592917178} 705 | ``` 706 | 707 | * id (activityId?), clubId, nadeo, roomId, campaignId, playerServerLogin, acitivityId, mediaUrl, name, room with id, name, region, serverAccountId, maxPlayers, playersCount, maps array, script, scriptSettings, serverInfo, and then popularityLevel, creationTimestamp 708 | 709 | ## GET /api/token/club/bucket/skin-upload/all 710 | 711 | ### Use: 712 | 713 | Not 100% sure but I think is related to see the skins uploaded by the clubs 714 | 715 | ### Request: 716 | 717 | #### Headers: 718 | 719 | *General Headers 1 and 2.2* 720 | 721 | #### Params: 722 | 723 | * offset=*number, example: 0* 724 | * length=*number, example: 75* 725 | * sort=popularity (*maybe other type of sort available idk*) 726 | * order=DESC (*maybe other type of order available idk*) 727 | 728 | ### Response: 729 | 730 | #### Headers: 731 | 732 | *General Response 1* 733 | 734 | #### Body: 735 | 736 | * ```json 737 | {"clubBucketList":[{"type":"skin-upload","bucketItemList":[],"bucketItemCount":2,"popularityLevel":3,"popularityValue":16055,"mediaUrl":"http:\/\/trackmania-prod-nls-file-store-s3.mdc.akamaized.net\/club\/54\/activity\/77\/5eddfd4a27fdf.png?updateTimestamp=1591606604.png","id":77,"clubId":54,"name":"zT Official Skin","creationTimestamp":1591606601}, ......], "maxPage":11, "itemCount":769} 738 | ``` 739 | 740 | * clubBucketList array with objects having type(skin-upload), bucketItemList (always empty?), bucketItemCount, popularityLevel, popularityValue, mediaUrl, id, clubId, name and creationTimestamp, and then maxPage and itemCount 741 | 742 | ## GET /api/token/map-review/waiting-time 743 | 744 | ### Use: Check the waiting time of the Map Review 745 | 746 | ### Request: 747 | 748 | #### Headers: 749 | 750 | *General Headers 1 and 2.2* 751 | 752 | ### Response: 753 | 754 | #### Headers: 755 | 756 | *General Response 1* 757 | 758 | * ```json 759 | {"seconds":360} 760 | ``` 761 | 762 | ## GET /api/token/map-review/connect 763 | 764 | ### Use: 765 | 766 | Used to get the URL the game uses internally to connect to a server that have maps to review 767 | 768 | ### Request: 769 | 770 | #### Headers: 771 | 772 | *General Headers 1 and 2.2* 773 | 774 | ### Response: 775 | 776 | #### Headers: 777 | 778 | *General Response 1* 779 | 780 | #### Body: 781 | 782 | * ```json 783 | {"joinLink":"#qjoin=ZQKOM8ZaRa2EhZeUBWcoMw"} 784 | ``` -------------------------------------------------------------------------------- /Login.md: -------------------------------------------------------------------------------- 1 | # Login Process and Tokens 2 | 3 | ## Login Process 4 | 5 | For the game to work, first we need to authenticate. The next picture ilustrates the process of login in the APIs and how the different tokens have different uses 6 | 7 | ![LoginProcess](loginTrackmania.png) 8 | 9 | *Although this is the primary login process, there's more like we found in the UbiServices* 10 | 11 | As you can see, you only need to use the Login Level 0, 1 and 2 only one time, after that you only need to refresh the token from Level 1 and 2 without needing for Uplay login anymore. 12 | 13 | ### Login Process Example 14 | 15 | ### Token Level 0 16 | 17 | For the level 0 token we need to do the following: 18 | 19 | POST Request 20 | URL: https://public-ubiservices.ubi.com/v3/profiles/sessions 21 | 22 | Header: 23 | | Key | Value | 24 | |---------------------------|--------------------------------------| 25 | | Authorization | Basic \ | 26 | | Ubi-AppId | 86263886-327a-4328-ac69-527f0d20a237 | 27 | | Ubi-RequestedPlatformType | uplay | 28 | | Content-Type | application/json | 29 | | User-Agent | \ | 30 | 31 | For the User-Agent you sometimes need to out something in there like "PostmanRuntime/7.28.4". 32 | I tried to send a request via python without the User-Agend field and it didn't work and only worked after adding it. So i am guessing that it is needed. 33 | 34 | To get the basic-encodedString you need to append your ubisoft email with a ':' and then append this new string again with your ubisoft passwort. After that encode this string in base64. 35 | 36 | eg. 37 | ``` 38 | basic-encodedString = encodeBase64("" + ":" + "") 39 | ``` 40 | 41 | Body: is not needed (None) 42 | 43 | After sending this request you will get a response that looks like this: 44 | 45 | ```json 46 | { 47 | "platformType": "uplay", 48 | "ticket": "", 49 | "twoFactorAuthenticationTicket": null, 50 | "profileId": "", 51 | "userId": "", 52 | "nameOnPlatform": "", 53 | "environment": "Prod", 54 | "expiration": "2021-10-28T02:07:39.9132598Z", 55 | "spaceId": "", 56 | "clientIp": "", 57 | "clientIpCountry": "", 58 | "serverTime": "2021-10-27T23:07:39.9159598Z", 59 | "sessionId": "", 60 | "sessionKey": "", 61 | "rememberMeTicket": null 62 | } 63 | ``` 64 | From this response you need to copy the string from the "ticket" field (very long string). 65 |
This string is the level 0 token. 66 | 67 | ### Token Level 1 68 | 69 | For the level 1 token you need to have a level 0 token and do the following: 70 | 71 | POST Request URL: https://prod.trackmania.core.nadeo.online/v2/authentication/token/ubiservices 72 | 73 | Header: 74 | | Key | Value | 75 | |---------------|---------------------------| 76 | | Authorization | ubi_v1 t=\| 77 | 78 |
79 | Body: is not needed (None) 80 |

81 | After sending this request you will get a response that looks like this: 82 | 83 | ```json 84 | { 85 | "accessToken": "", 86 | "refreshToken": "" 87 | } 88 | ``` 89 | 90 | The string that is stored in the accessToken field is the level 1 token and the string stored in the refreshToken field it the token that can be used to get a new accessToken and refreshToken if the current accessToken for level 1 is expired. 91 | 92 | ### Token Level 2 93 | 94 | For the level 1 token you need to have a level 1 token and do the following: 95 | 96 | POST Request URL: https://prod.trackmania.core.nadeo.online/v2/authentication/token/nadeoservices 97 | 98 | Header: 99 | | Key | Value | 100 | |---------------|-----------------------------| 101 | | Authorization | nadeo_v1 t=\| 102 | 103 |
104 | Body: should be JSON 105 | 106 | ```json 107 | {"audience" : "NadeoLiveServices"} 108 | ``` 109 | The value in the body can be changed, to fit the service you try to authenticate with. In this example we try to authenticate at the "nadeo live services". 110 | 111 |

112 | After sending this request you will get a response that looks like this: 113 | 114 | ```json 115 | { 116 | "accessToken": "", 117 | "refreshToken": "" 118 | } 119 | ``` 120 | 121 | The string that is stored in the accessToken field is the level 2 token and the string stored in the refreshToken field it the token that can be used to get a new accessToken and refreshToken if the current accessToken for level 2 is expired. 122 | 123 | Now we have aquired all tokens and can access the APIs. 124 | 125 | ## Tokens 126 | 127 | The tokens that are being used in the process described before are of JWT type. So, if we try to decode them we get: 128 | 129 | ### Ticket Value from Response Level 0 130 | 131 | This one is encrypted, probably because this response come from UbisoftServers to login on Uplay. We are only able to check their headers, that confirm the JWT token is a encrypted one (*JWE*) 132 | 133 | ```json 134 | { 135 | "ver": "1", 136 | "aid": "*someId*", 137 | "env": "Prod", 138 | "sid": "*someId*", 139 | "typ": "JWE", 140 | "enc": "A128CBC", 141 | "iv": "*inicializerVector*", 142 | "int": "HS256" 143 | } 144 | ``` 145 | 146 | *Missing description* 147 | 148 | ### Access Token Value from Response Level 1 and 2 149 | 150 | This response came from the Trackmania API and this one is ***not*** encrypted. If we check the headers and payload of the JWT we get this: 151 | 152 | **Header** 153 | 154 | ```json 155 | { 156 | "typ": "JWT", 157 | "alg": "HS256", 158 | "env": "trackmania-prod", 159 | "ver": "1" 160 | } 161 | ``` 162 | 163 | **Body** 164 | 165 | ```json 166 | { 167 | "jti": "*someId*", 168 | "iss": "NadeoServices", 169 | "iat": 1595707067, 170 | "rat": 1595708867, 171 | "exp": 1595710667, 172 | "aud": "NadeoServices", 173 | "usg": "Client", 174 | "sid": "*someId*", 175 | "sub": "*accountId*", 176 | "aun": "*username*", 177 | "rtk": false, 178 | "pce": false, 179 | "ubiservices_pid": "*someId*" 180 | } 181 | ``` 182 | 183 | **iss** is the name of the issuer, **exp** tells use the time until the token is valid, **rat** the time where after that we can refresh our token, **aud** is for where the token is to be used (Level 1 says NadeoServices, but Level 2 can say NadeoLiveServices or other), **usg** the type of use, **sub** is our accountId (this is were we know our accountId on the game), **aun** is our username. The **sid** is the same for both accessToken and refreshToken, and Level 1 and 2, although I don't know what is this. *Missing more description* 184 | 185 | ### Refresh Token Value from Response Level 1 and 2 186 | 187 | The header JWT is the same as the last one, the body have this structure: 188 | 189 | ```json 190 | { 191 | "jti": "*someId*", 192 | "iss": "NadeoServices", 193 | "iat": 1595707067, 194 | "rat": 1595750267, 195 | "exp": 1595793467, 196 | "aud": "NadeoServices", 197 | "usg": "Client", 198 | "sid": "*someId*", 199 | "sub": "*accountId*", 200 | "aun": "*username*", 201 | "rtk": true, 202 | "pce": false, 203 | "ubiservices_pid": "*someId*", 204 | "refresh_aud": "NadeoServices", 205 | "limit_type": "none" 206 | } 207 | ``` 208 | 209 | We can see that this one have **rtk** to true (although I don't know what is this), and have a **refresh_aud** (Level 1 says NadeoServices, but Level 2 can say NadeoLiveServices or other), and a **limit_type**. *Missing more description* 210 | 211 | -------------------------------------------------------------------------------- /MSR-Akamai.md: -------------------------------------------------------------------------------- 1 | # Routes msr-public.aws-ubiservices.ubi.com 2 | 3 | ## GET /v4/spaces/*profileId*/configs/events 4 | 5 | ### Use: 6 | 7 | Is used to obtain events, I think Uplay(?) wants to track you down like opening the game, entering a server, etc. 8 | 9 | ### Request: 10 | 11 | #### Headers: 12 | 13 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 14 | * Accept: \*/\* 15 | * Authorization: Ubi_v1 t=*ticket value from UbiServices POST /v3/profiles/session* 16 | * Content-Type: application/json 17 | * ubi-appbuildid: 202007232022 18 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 19 | * Ubi-localeCode: *localeCode* 20 | * Ubi-Populations: US_EMPTY_VALUE 21 | * Ubi-SessionId: *SessionId* 22 | 23 | ### Response: 24 | 25 | #### Headers: 26 | 27 | * X-Powered-By: Express 28 | * ETag: *Etag* 29 | * Vary: Accept-Encoding 30 | * Ubi-Forwarded-By: msr-us-nginx07 31 | * Ubi-TransactionId: *TransactionId* 32 | * Strict-Transport-Security: max-age=63072000 33 | * X-Frame-Options: DENY 34 | * X-Content-Type-Options: nosniff 35 | 36 | #### Body: 37 | 38 | * ```json 39 | {"types":["game.localization","game.start","player.start","player.stats.playtime","context.start.gameMode","context.stop.gameMode","context.start.map","context.stop.map","context.stop.play","context.start.play","custom.newMapCreated","custom.stats.medal","player.progression.medal"],"s2sConfig":{"maxBatchSize":2500,"sendPeriodSeconds":1},"publicConfig":{"sendPeriodSeconds":30,"hmacEnabled":false}} 40 | ``` 41 | 42 | ## POST /v3/profiles/me/events 43 | 44 | ***Needs more info cause the game makes a lot of this requests*** 45 | 46 | ### Use: 47 | 48 | Updates what the user is doing in the game 49 | 50 | ### Request: 51 | 52 | #### Headers: 53 | 54 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 55 | * Accept: \*/\* 56 | * Authorization: Ubi_v1 t=*ticket value from UbiServices POST /v3/profiles/session* 57 | * Content-Type: application/json 58 | * ubi-appbuildid: 202007232022 59 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 60 | * Ubi-localeCode: xx-PT 61 | * Ubi-Populations: US_EMPTY_VALUE 62 | * Ubi-SessionId: 5090d904-ec68-47bd-9013-db82432ff5dc 63 | * Content-Length: 1274 64 | * Expect: 100-continue 65 | 66 | #### Body: 67 | 68 | * ```json 69 | {"events":[{"createdDate":"2020-07-24T18:15:35.590Z","obj":{},"typeData":{"machineId":"*machineId*","buildVersion":"202007232022","gameVersion":"Full","gameSku":"PC-WW","usSdkVersion":"2019.Release.13"},"type":"game.start","seqId":0,"contexts":[]},{"createdDate":"2020-07-24T18:15:45.503Z","obj":{"gameVersion":"Full"},"typeData":{"abtesting":{},"platformType":"uplay"},"type":"player.start","absolutePlaytime":*absolutePlayTime*,"relativePlaytime":0,"seqId":1,"contexts":[]},{"createdDate":"2020-07-24T18:15:45.503Z","obj":{"soloPlaytimeAbsolute":*soloPlaytimeAbsolute*,"livePlaytimeAbsolute":*livePlaytimeAbsolute*,"clubPlaytimeAbsolute":*clubPlaytimeAbsolute*,"localPlaytimeAbsolute":*localPlaytimeAbsolute*,"createPlaytimeAbsolute":*createPlaytimeAbsolute*},"typeData":{"playtimeAbsolute":*playtimeAbsolute*,"playtimeRelative":0},"type":"player.stats.playtime","absolutePlaytime":*absolutePlaytime*,"relativePlaytime":0,"seqId":2,"contexts":[]},{"createdDate":"2020-07-24T18:15:49.919Z","obj":{},"typeData":{"menuLanguage":"en-US","audioLanguage":"en-US","platformLanguage":"*plataformLanguage*","areSubtitlesEnabled":false,"subtitlesLanguage":"none"},"type":"game.localization","absolutePlaytime":*absolutePlaytime*,"relativePlaytime":4,"seqId":3,"contexts":[]}],"gameSessionId":"*sessionId*","playerSessionId":"*sessionId*","spaceId":"*spaceId/profileId(?)*" } 70 | ``` 71 | 72 | --- 73 | 74 | # Routes akamai.net (a1944.dscd.akamai.net) 75 | 76 | ## GET /club/*clubId*/activity/*nameContent* (ex:/club/3118/activity/65804/5f18c059062cf.png?updateTimestamp=1595457628.png) 77 | 78 | ### Use: 79 | 80 | Download stuff like images 81 | 82 | ### Request: 83 | 84 | #### Headers: 85 | 86 | * Accept: \*/\* 87 | * User-Agent: ManiaPlanet/3.3.0 (Win64; rv: 2020-07-23_20_22; context: none; distro: UPLAY) 88 | * Accept-Encoding: gzip,deflate 89 | * Accept-Language: en-US,en 90 | 91 | ### Response: 92 | 93 | * The content(an image, etc.) -------------------------------------------------------------------------------- /ProdTrackmania.md: -------------------------------------------------------------------------------- 1 | # Routes prod.trackmania.core.nadeo.online 2 | 3 | Because most of the time the game uses the same headers, the next headers are considered "general headers", and then in every endpoint I will specify with just a number the headers needed, and that number represent the same number I list the headers in this section. 4 | 5 | ***If I put in the JSON Responses \*\* is because I want to hide sensitive information*** 6 | 7 | ## General Headers 8 | 9 | #### 1 (I dont think this headers are needed, I can make the same requests without this, so probably you can ignore this headers) 10 | 11 | * User-Agent: ManiaPlanet/3.3.0 (Win64; rv: 2020-07-23_20_22; context: none; distro: UPLAY) 12 | * Pragma: no-cache 13 | * Cache-Control: no-cache, no-store, must-revalidate 14 | * Accept-Encoding: gzip,deflate 15 | * Accept-Language: en-US,en 16 | * Nadeo-Game-Build: 2020-07-23_20_22 17 | * Nadeo-Game-Distro: UPLAY 18 | * Nadeo-Game-Lang: en-US 19 | * Nadeo-Game-Name: ManiaPlanet 20 | * Nadeo-Game-Version: 3.3.0 21 | 22 | #### 2 23 | 24 | Authorization: nadeo_v1 t= 25 | 26 | ##### 2.1 27 | 28 | accessToken from Level 1 29 | 30 | ##### 2.2 31 | 32 | accessToken from Level 2 - NadeoLiveServices 33 | 34 | ##### 2.3 35 | 36 | accessToken from Level 2 - NadeoClubServices 37 | 38 | 39 | ## General Response 40 | 41 | #### 1 42 | 43 | * Vary: Authorization 44 | 45 | --- 46 | --- 47 | 48 | ## GET /client/config 49 | 50 | ### Use: 51 | 52 | To get the configuration of a client 53 | 54 | ### Request 55 | 56 | #### Headers: 57 | 58 | *General Header 1* 59 | 60 | ### Response 61 | 62 | #### Body: 63 | 64 | * ```json 65 | {"keys":[{"id":1,"timeout":2592000,"key":"*key*"},{"id":2,"timeout":2592000,"key":"*key*"},{"id":3,"timeout":2592000,"key":"*key*"}],"settings":{"KillSwitch_ProfileChunk":1,"KillSwitch_TitleConfig":1,"KillSwitch_TitleLadder":1,"KillSwitch_TitlePolicy":1,"KillSwitch_TitleProfileChunk":1,"KillSwitch_Xp":1,"AdsClearCacheOnExit":0,"AdsMandatory":0,"MapRecordResetTimestamp":0,"ClientIP":"*ip*"}} 66 | ``` 67 | 68 | * 3 Keys with id and timeout, and settings 69 | 70 | ## PUT /waitingQueue/*some id* 71 | 72 | ### Use: 73 | 74 | ***Idk*** 75 | 76 | ### Request: 77 | 78 | #### Headers: 79 | 80 | * *General Header 1* 81 | 82 | ### Response: 83 | 84 | #### Body: 85 | 86 | * ```json 87 | {"rank":0,"refreshTime":900,"timestamp":"2020-07-24T18:15:51+00:00","waitingTime":0} 88 | ``` 89 | 90 | * rank is the position in the waitingQueue (0 is for no waitingQueue), refreshTime, timestamp and waitingTime 91 | 92 | ## POST /v2/authentication/token/ubiservices 93 | 94 | ### Use: 95 | 96 | Login to get a Level 1 Token using the credentials from the Uplay 97 | 98 | ### Request: 99 | 100 | #### Headers: 101 | 102 | * *General Header 1* 103 | * Authorization: ubi_v1 t=***ticketValueFromTheLevel0Login*** 104 | 105 | ### Response: 106 | 107 | #### Headers: 108 | 109 | *General Response 1* 110 | 111 | #### Body: 112 | 113 | * ```json 114 | {"accessToken":"*token*","refreshToken":"*token*"} 115 | ``` 116 | 117 | * accessToken and refreshToken 118 | 119 | ## PUT /accounts/*accountId*/presence 120 | 121 | ### Use: 122 | 123 | Notify the Trackmania Servers that this user is online (???) 124 | 125 | ### Request: 126 | 127 | #### Headers: 128 | 129 | *General Headers 1 and 2.1* 130 | 131 | ### Response: 132 | 133 | #### Headers: 134 | 135 | *General Response 1* 136 | 137 | #### Body: 138 | 139 | * ```json 140 | {"accountId":"*accountId*","isOnline":true,"refreshTime":900} 141 | ``` 142 | 143 | * accountId confirmation, isOnline e refreshTime 144 | 145 | ## GET /accounts/*accountId*/policies/global/rules 146 | 147 | ### Use: 148 | 149 | Get all the policies associated with a user (?) 150 | 151 | ### Request: 152 | 153 | #### Headers: 154 | 155 | *General Headers 1 and 2.1* 156 | 157 | ### Response: 158 | 159 | #### Headers: 160 | 161 | *General Response 1* 162 | 163 | #### Body: 164 | 165 | * ```json 166 | [{"policyRuleId":"052d3167-df15-4279-a8a3-37eda62b5065","policyRuleName":"client_OpenMainMenu","policyRuleValue":"1"}, ......] 167 | ``` 168 | 169 | * Array of policyRuleId, policyRuleName and policyRuleValue 170 | 171 | ## GET /accounts/*accountId*/client/config 172 | 173 | ### Use: 174 | 175 | Get the configuration of the client from this account 176 | 177 | ### Request: 178 | 179 | #### Headers: 180 | 181 | *General Headers 1 and 2.1* 182 | 183 | ### Response: 184 | 185 | #### Headers: 186 | 187 | *General Response 1* 188 | 189 | #### Body: 190 | 191 | * ```json 192 | {"settings":{"CDVBase":*number*,"CDVSignature":"*signature*","CDVSignatureKeyId":*number*,"PackageKeyDeleteThreshold":*number*,"PackageKeyExpirationThreshold":*number*}} 193 | ``` 194 | 195 | * settings containing CSVBase, CSVSignature, CSVSignatureKeyId, PackageKeyDeleteThreshold and PackageKeyExpirationThreshold 196 | 197 | ## GET /accounts/*accountId*/client/signature 198 | 199 | ### Use: 200 | 201 | Download the client signature 202 | 203 | ### Request: 204 | 205 | #### Headers: 206 | 207 | *General Headers 1 and 2.1* 208 | 209 | #### Params: 210 | 211 | * signature=*id related to last endpoint described* 212 | 213 | ### Response 214 | 215 | #### Headers: 216 | 217 | *General Response 1* 218 | 219 | #### Body: 220 | 221 | * ```json 222 | {"signature":"*signature*","public_key_id":1} 223 | ``` 224 | 225 | * signature, public_key_id = 1(maybe deactivated or not used) 226 | 227 | ## GET /accounts/*accountId*/encryptedPackage/key 228 | 229 | ### Use: 230 | 231 | Download the public key of the user 232 | 233 | ### Request: 234 | 235 | #### Headers: 236 | 237 | *General Headers 1 and 2.1* 238 | 239 | ### Response: 240 | 241 | #### Headers: 242 | 243 | *General Response 1* 244 | 245 | #### Body: 246 | 247 | * ```text 248 | "-----BEGIN PUBLIC KEY-----*public Key*-----END PUBLIC KEY-----\n" 249 | ``` 250 | 251 | * Public Key, idk when is used 252 | 253 | ## GET /client/updaters/current 254 | 255 | **This returns HTTP 422 Unprocessable Entity, still I will document how the game requested** 256 | 257 | ### Use: 258 | 259 | ***Idk*** 260 | 261 | ### Request: 262 | 263 | #### Headers: 264 | 265 | *General Headers 1 and 2.1* 266 | 267 | ### Response: 268 | 269 | #### Headers: 270 | 271 | *General Response 1* 272 | 273 | #### Body: 274 | 275 | * ```json 276 | {"code":"C-AD-01-01","correlation_id":"*id*","error_id":"0ecd55a7-bb50-4805-ae85-3711de0ad315","message":"Unknown client updater."} 277 | ``` 278 | 279 | * ***Error, idk why*** 280 | 281 | ## GET /accounts/*accountId*/client/urls 282 | 283 | ### Use: 284 | 285 | ***Idk*** 286 | 287 | ### Request: 288 | 289 | #### Headers: 290 | 291 | *General Headers 1 and 2.1* 292 | 293 | ### Response 294 | 295 | #### Headers: 296 | 297 | *General Response 1* 298 | 299 | #### Body: 300 | 301 | * ```json 302 | {"test":"http:\/\/test.nadeo.com"} 303 | ``` 304 | 305 | * ***maybe not used at all, or only used with specific conditions?*** 306 | 307 | ## GET /accounts/*accountId*/client/plugins 308 | 309 | ### Use: 310 | 311 | **Idk** 312 | 313 | ### Request: 314 | 315 | #### Headers: 316 | 317 | *General Headers 1 and 2.1* 318 | 319 | ### Response: 320 | 321 | #### Headers: 322 | 323 | *General Response 1* 324 | 325 | #### Body: 326 | 327 | * ```json 328 | ["Media\/ManiaApps\/Nadeo\/System\/TrackmaniaAuth.Script.txt","Media\/ManiaApps\/Nadeo\/System\/keys\/Keys.Script.txt","Media\/ManiaApps\/Nadeo\/System\/report\/Report.Script.txt","Media\/ManiaApps\/Nadeo\/System\/settings\/Settings.Script.txt"] 329 | ``` 330 | 331 | * Array containing list of scripts, this one are default i guess 332 | 333 | ## GET /zones 334 | 335 | ### Use: 336 | 337 | Get all the IDs from all the zones for internal use and to be able to call endpoints using this IDs 338 | 339 | ### Request: 340 | 341 | #### Headers: 342 | 343 | *General Headers 1 and 2.1* 344 | 345 | ### Response: 346 | 347 | #### Headers: 348 | 349 | *General Response 1* 350 | 351 | #### Body (description of content) 352 | 353 | * Big JSON with all the zones ids, names, links to flags, etc. 354 | * Each zone has an identifier called **zoneId** and it can be a children of other zones, so there is also a **parentId** 355 | * The root of all zones is World that has a null parentId 356 | 357 | ## GET /accounts/*accountId*/zone 358 | 359 | ### Use: 360 | 361 | Get Player Zone 362 | 363 | ### Request: 364 | 365 | #### Headers: 366 | 367 | *General Headers 1 and 2.1* 368 | 369 | ### Response 370 | 371 | #### Headers: 372 | 373 | *General Response 1* 374 | 375 | #### Body: 376 | 377 | * ```json 378 | {"accountId":"*accountId*","timestamp":"2020-07-01T16:56:00+00:00","zoneId":"*zoneId*"} 379 | ``` 380 | 381 | * accountId: again 382 | * timestamp: first time you joined Trackmania. In the above example it was on 2020-07-01, the day of game's launch 383 | * zoneId: ID of the zone of the player. See GET /zones for more info. 384 | 385 | --- 386 | 387 | **This was all the requests the game make when you open Trackmania** 388 | 389 | --- 390 | 391 | ## POST /v2/authentication/token/nadeoservices 392 | 393 | ### Use: 394 | 395 | Login to get a Level 2 Token to be used in NadeoLiveServices, using the Level 1 token 396 | 397 | ### Request: 398 | 399 | #### Headers: 400 | 401 | * *General Headers 1 and 2.1* 402 | 403 | * Content-Type: application/json 404 | 405 | #### Body: 406 | 407 | * ```json 408 | {"audience" : "NadeoLiveServices"} 409 | ``` 410 | 411 | or 412 | 413 | * ```json 414 | {"audience" : "NadeoClubServices"} 415 | ``` 416 | 417 | The type of audience used will affect where the token can be used 418 | 419 | ***Note that if you don't provide a json body, you get a token for audience `NadeoServices`*** 420 | 421 | ### Response: 422 | 423 | #### Headers: 424 | 425 | *General Response 1* 426 | 427 | #### Body: 428 | 429 | * ```json 430 | {"accessToken":"*token*","refreshToken":"*token*"} 431 | ``` 432 | 433 | * accessToken and refreshToken 434 | 435 | ## POST /v2/authentication/token/basic 436 | 437 | ### Use: 438 | 439 | Login using Basic Authentication 440 | 441 | ### Request: 442 | 443 | #### Headers: 444 | 445 | * Authorization: Basic authentication with username/password set to your dedicated server login/password 446 | * Content-type: application/json 447 | 448 | #### Body: 449 | 450 | * ```json 451 | {"audience" : "NadeoLiveServices"} 452 | ``` 453 | 454 | or 455 | 456 | * ```json 457 | {"audience" : "NadeoClubServices"} 458 | ``` 459 | 460 | The type of audience used will affect where the token can be used 461 | 462 | ***Note that if you don't provide a json body, you get a token for audience `NadeoServices`*** 463 | 464 | ### Response: 465 | 466 | #### Headers: 467 | 468 | *General Response 1* 469 | 470 | #### Body: 471 | 472 | * ```json 473 | {"accessToken":"*token*","refreshToken":"*token*"} 474 | ``` 475 | 476 | * accessToken and refreshToken 477 | 478 | ## GET /mapRecords 479 | 480 | ### Use: 481 | 482 | Get more info about a record, and the url leads to a ghost file, that you can use to download and played it on the replay editor (***check some relevant use cases README about how you can watch a ghost file on Trackmania***) 483 | 484 | ### Request: 485 | 486 | #### Headers: 487 | 488 | *General Headers1 and 2.1* 489 | 490 | #### Params: 491 | 492 | ##### Required 493 | 494 | * accountIdList - list of accountIds 495 | * seasonId - ID of the season 496 | * mapIdList - IDs of the map to lookup 497 | 498 | ##### Optional 499 | 500 | * addPersonalBest - true or false, idk what is this for 501 | 502 | ### Response: 503 | 504 | #### Headers: 505 | 506 | *General Response 1* 507 | 508 | #### Body: 509 | 510 | * ````json 511 | [{"accountId":"*accountId*","filename":"*filename.replay.gbx*","gameMode":"TimeAttack","gameModeCustomData":"","mapId":"*mapId*","medal":4,"recordScore":{"respawnCount":4294967295,"score":0,"time":36217},"removed":false,"scopeId":"*scopeId*","scopeType":"Season","timestamp":"2020-07-05T12:57:04+00:00","url":"*url*"}, .........] 512 | ```` 513 | 514 | 515 | 516 | ## GET /maps 517 | 518 | ### Use: 519 | 520 | Get info about a map and be able to download the map with the link included in the response. **Comes in 2 variants: MapIdList and MapUidList** 521 | 522 | ### Request: 523 | 524 | #### Headers: 525 | 526 | *General Headers 1 and 2.1* 527 | 528 | #### Params: 529 | 530 | ##### Required: 531 | 532 | * mapIdList = List of Map Ids separated by %2c 533 | 534 | or 535 | 536 | * mapUidList=List of map Uids separated by %2c 537 | 538 | ### Response: 539 | 540 | #### Headers: 541 | 542 | *General Response 1* 543 | 544 | #### Body: 545 | 546 | * ```json 547 | [{"author":"*accountId*","authorScore":69537,"bronzeScore":105000,"collectionName":"Stadium","environment":"Stadium","filename":"Formule Gou1 .Map.Gbx","goldScore":74000,"isPlayable":true,"mapId":"*mapId*","mapUid":"*mapUid*","name":"Formule Gou1 ","silverScore":84000,"submitter":"*accountId*","timestamp":"2020-07-20T12:23:02+00:00","fileUrl":"https:\/\/prod.trackmania.core.nadeo.online\/storageObjects\/5d095673-130d-449a-a992-9eca4caab4ee","thumbnailUrl":"https:\/\/prod.trackmania.core.nadeo.online\/storageObjects\/4778b079-af49-4234-9e2b-beb60f1d901d.jpg"}, ***...***] 548 | ``` 549 | 550 | * List of objects with author, authorScore, bronzeScore, silverScore, goldScore, collectionName (*always Stadium?*), environment (*always Stadium?*), filename, isPlayable,mapId,mapUid,name,submitter (*not confirmed but probably accountId*), timestamp, fileUrl, thumbnailUrl 551 | 552 | ## GET /trophies/settings 553 | 554 | ### Use: 555 | 556 | Get User Trophies 557 | 558 | ### Request: 559 | 560 | #### Headers: 561 | 562 | *General Headers 1 and 2.1* 563 | 564 | ### Response: 565 | 566 | #### Headers: 567 | 568 | *General Response 1* 569 | 570 | #### Body: 571 | 572 | * ```json 573 | {"gain":{"Solo":{"SoloMedal":{"ClubOfficial":{"allBronze":{"t1Count":1},"allSilver":{"t2Count":1},"allGold":{"t3Count":1},"allAuthor":{"t4Count":1}},"ClubUnofficial":{"allSilver":{"t1Count":1},"allGold":{"t2Count":1},"allAuthor":{"t3Count":1}},"SoloAll":{"allAuthor":{"t5Count":5}},"SoloBlack":{"allBronze":{"t2Count":1},"allSilver":{"t3Count":1},"allGold":{"t4Count":1},"allAuthor":{"t5Count":1}},"SoloBlue":{"allBronze":{"t1Count":1},"allSilver":{"t2Count":1},"allGold":{"t3Count":1},"allAuthor":{"t4Count":1}},"SoloGreen":{"allBronze":{"t1Count":1},"allSilver":{"t2Count":1},"allGold":{"t3Count":1},"allAuthor":{"t4Count":1}},"SoloRed":{"allBronze":{"t2Count":1},"allSilver":{"t3Count":1},"allGold":{"t4Count":1},"allAuthor":{"t5Count":1}},"SoloWhite":{"allBronze":{"t1Count":1},"allSilver":{"t2Count":1},"allGold":{"t3Count":1},"allAuthor":{"t4Count":1}},"TrackOfTheDay":{"allGold":{"t3Count":1},"allAuthor":{"t4Count":1}}}}}} 574 | ``` 575 | 576 | * An object called Gain, with only another object called Solo, and then SoloMedal, and then for every other object inside this one (ClubOfficial, ClubUnofficial, SoloAll, SoloBlack, SoloBlue, SoloGreen, SoloRed, SoloWhite, TrackOfTheDay) it returns if the person obtained all bronze, silver, gold and author medal of that group. Maybe the solo trophies are calculated by checking if the user already win all the medals from specific group? 577 | 578 | 579 | ## GET /seasons/*seasonid* 580 | 581 | ### Use: 582 | 583 | Get info about a season, with all the details, included info about map ids 584 | 585 | ### Request: 586 | 587 | #### Headers: 588 | 589 | *General Headers 1 and 2.1* 590 | 591 | ### Response: 592 | 593 | #### Body: 594 | 595 | * ````json 596 | {"creationTimestamp":"2020-06-23T17:08:48+00:00","creatorId":"f4c1d5cd-a018-402e-b69c-152f41ad1684","endTimestamp":"2100-01-01T00:00:00+00:00","gameMode":"TimeAttack","gameModeCustomData":"","isOfficial":true,"name":"Summer 2020 #1","recordScoreType":"Time","seasonId":"3987d489-03ae-4645-9903-8f7679c3a418","seasonMapList":[{"mapId":"20fbc899-920e-471c-a07e-d2bfabcaff06","timestamp":"2020-06-23T17:08:48+00:00"}, .........], "startTimestamp":"2020-06-23T17:08:00+00:00"} 597 | ```` 598 | 599 | * creationTimestamp, creatorId, endTimestamp, gameMode, gameModeCustomData, isOfficial, name, recordScoreType, seasonId, seasonMapList with objects with mapId and timestamp, and startTimestamp 600 | 601 | ## GET /webidentities 602 | 603 | ### Use: 604 | 605 | Get profile id's based on account ids 606 | 607 | ### Request: 608 | 609 | #### Headers: 610 | 611 | **1 and 2.1** 612 | 613 | #### Params: 614 | 615 | ##### Required: 616 | 617 | * accountIdList = list of accountIds separated by %2c 618 | 619 | ### Response: 620 | 621 | #### Headers: 622 | 623 | *General Response 1* 624 | 625 | #### Body: 626 | 627 | * ````json 628 | [{"accountId":"*accountId*","provider":"ubiServices","uid":"*profileId*","timestamp":"2020-05-07T21:15:24+00:00"}] 629 | ```` 630 | 631 | * array of accountId, provider, uid and timestamp 632 | 633 | ## HEAD /storageObjects/*someFileName* 634 | 635 | ***This Redirects to others servers, probably to load balancing between different servers since is for downloading archives*** 636 | 637 | ### Use: 638 | 639 | Obtain address of location of the file we want to download 640 | 641 | ### Request: 642 | 643 | #### Headers: 644 | 645 | * Accept-Encoding: deflate, gzip 646 | * User-Agent: ManiaPlanet/3.3.0 (Win64; rv: 2020-07-23_20_22; context: none; distro: UPLAY) 647 | * Accept-Language: en-US,en 648 | 649 | ### Response (Status Code and Headers) 650 | 651 | HTTP Code 307 with Location Header having a URL to the file 652 | 653 | ## GET /encryptedPackages/versions 654 | 655 | ### Use: 656 | 657 | **Idk, but this is used when we want to upload a new mapRecord** 658 | 659 | ### Request: 660 | 661 | #### Headers: 662 | 663 | *General Headers 1 and 2.1* 664 | 665 | #### Params: 666 | 667 | * checksumList=*checksum* 668 | 669 | ### Response 670 | 671 | #### Headers: 672 | 673 | *General Response 1* 674 | 675 | #### Body: 676 | 677 | * ````json 678 | [{"contentChecksum":"*someChecksum*","encryptedPackageId":"*Id*","encryptedPackageVersionId":"*version*","impostorUrl":"*link*","timestamp":"*timestamp*"}] 679 | ```` 680 | 681 | * contentChecksum, encryptedPackageId, encryptedPackageVersionId, impostorUrl, timestamp 682 | * The Url transfer a Pack File 683 | * ***Idk where the checksum used in the request URI came from*** 684 | 685 | ## POST /mapRecords 686 | 687 | ### Use: 688 | 689 | Upload a new map record 690 | 691 | ### Request: 692 | 693 | #### Headers: 694 | 695 | * *General Headers 1 and 2.1* 696 | * Content-Type: multipart/form-data; boundary=Boundary 697 | * Content-Length: 62772 698 | 699 | #### Body: 700 | 701 | * MultiPart file, one part with json and another with binary content (equivalent to a GBX file representing a Ghost File) 702 | 703 | JSON Content: 704 | 705 | * ````json 706 | {"recordScore" : {"time" : *time*,"score" : 0,"respawnCount" : 4294967295},"medal" : 1,"gameModeCustomData" : "","gameMode" : "TimeAttack","exeVersion" : "Trackmania date=2020-07-23_20_22 Svn=106224 GameVersion=3.3.0","exeChecksum" : *exeChecksum*,"encryptedPackageVersionId" : "*PackageVersionID*","mapId" : "*mapId*"} 707 | ```` 708 | 709 | * the encryptedPackageVersionId is referent to the packageVersionId of the GET /encryptedPackages/versions/?checksumList=*checksum*, so they are correlated 710 | 711 | Binary Content: 712 | 713 | * Binary Content with the ghost file 714 | 715 | ### Response: 716 | 717 | ***Didnt find the response for this one and can't replicate, I will try making another record in a map to get the response*** 718 | 719 | ## GET /servers/*someId* 720 | 721 | ### Use: 722 | 723 | Get info about a server 724 | 725 | ### Request: 726 | 727 | #### Headers: 728 | 729 | *General Headers 1 and 2.1* 730 | 731 | ### Response: 732 | 733 | #### Headers: 734 | 735 | *General Response 1* 736 | 737 | #### Body: 738 | 739 | * ````json 740 | {"accountId":"*accountId*","gameMode":"TimeAttack","gameModeCustomData":"","ip":"*ip*","isPrivate":false,"login":"*login*","name":"Summer 2020","playerCount":21,"playerCountMax":75,"port":2368,"timestamp":"*timestamp*","titleId":"Trackmania"} 741 | ```` 742 | 743 | * accountId (creator of the server?), gameMode, gameModeCustomData, ip, isPrivate, login, name, playerCount, playerCountMax, port, timestamp, titleId 744 | 745 | ## GET /accounts/*accountId*/trophies/lastYearSummary 746 | 747 | ### Use: 748 | 749 | Get the current trophies from an account 750 | 751 | ### Request: 752 | 753 | #### Headers: 754 | 755 | *General Headers 1 and 2.1* 756 | 757 | ### Response: 758 | 759 | #### Headers: 760 | 761 | *General Response 1* 762 | 763 | #### Body: 764 | 765 | * ````json 766 | {"accountId":"*accountId*","points":499,"t1Count":9,"t2Count":19,"t3Count":3,"t4Count":0,"t5Count":0,"t6Count":0,"t7Count":0,"t8Count":0,"t9Count":0,"timestamp":"*timestamp*"} 767 | ```` 768 | 769 | * accountId, points, t1count, t2count, t3count, t4count, t5count, t6count, t7count, t8count, t9count (t* referent to the level of the trophies) 770 | 771 | 772 | 773 | ## TODO 774 | 775 | * Use this endpoint **GET /api/routes?usage=Client** or **GET /api/routes** to check for the others endpoints 776 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ATTENTION: This repository is deprecated, as I didn't updated ever since the first few commits. If you want to visit documentation that is being updated with the latest changes, please go to https://webservices.openplanet.dev/ (thank you [codecat](https://github.com/codecat)) 2 | 3 | # Trackmania 2020 Unofficial API Documentation (DEPRECATED) 4 | 5 | This repository is a series of markdown files containing all the documentation myself and others found about Trackmania 2020 and the API calls the game makes to work. 6 | 7 | ## Warning!! 8 | 9 | **This API is not intended to be used outside of the game!!** 10 | 11 | Be aware that Nadeo can change the API without even warning us, since the API is intended only to be used in game, so don't except any support for them, and don't try to make anything serious out of this 12 | 13 | Also, **don't abuse of this API, has they have the right to lock your account since, for them, it's someone that is trying to hack or just trying to give bad performance to the servers** 14 | 15 | ## Progress 16 | 17 | This is in a very begin phase so please pull request to help this project by fixing typos, fix errors, describe in more detail the use of the endpoints, helping in the structure of documentation, and most important add more information. 18 | 19 | Any help is appreciated! 20 | 21 | Also, if you have any project that you are developing and you are using this documentation to help you in the interaction with the Trackmania API you can share with me and I will be glad to share here your project. It can be a simple wrapper library or even a full app. 22 | 23 | ## TODO 24 | 25 | * **Since I don't have club access, I can't test some functions inside the game like rooms and clubs, so that part are lacking in this documentation. If you have club access and wants to help, but you dont want to give your credentials to me, you can DM me and I can say how you can help me** 26 | * **We still don't know how to get the accountId given an username. I ALREADY KNOW HOW TO GET THE PROFILEID!! But it seems that the Nadeo's API don't have any endpoint we can use to get the accountId from a profileId, until then the only way we can lookup data from a specific user is if the user logins with their Uplay account** 27 | 28 | ## Contributors 29 | 30 | * Myself, [The-Firexx](https://github.com/The-Firexx), for gathering most of this information and creating this repository 31 | * [Marco97pa](https://github.com/marco97pa) for helping on completing some information. 32 | * [Codecat](https://github.com/codecat) from showing some [information](https://gist.github.com/codecat/4dfd3719e1f8d9e5ef439d639abe0de4) about this, and suggest to add the warning about the use of Trackmania API. Also made this [plugin](https://openplanet.nl/files/49) for OpenPlanet to inspect the packets ingame 33 | * [Breeku](https://github.com/breeku) for helping on completing information about webidentities 34 | 35 | ## Projects using Trackmania API 36 | 37 | * [Breeku](https://github.com/breeku/) made a [npm module](https://github.com/breeku/trackmania-api-node) that helps developers to use the Trackmania API by abstracting the HTTP requests and wrap them in methods that can be called for a more easy use of the API in a program. He also made a [Trackmania Leaderboard Page](https://opentrackmania.com/) where you can lookup for TOTD, Season tracks and players present on the leaderboard | [Repo](https://github.com/breeku/opentrackmania) 38 | * [Jonese1234](https://github.com/jonese1234/) created a [Leaderboard Scraper](https://github.com/jonese1234/Trackmania-2020-Leaderboard-Scraper) that, although it started without help, is using this documentation to use more functions. 39 | * [Marco97pa](https://github.com/marco97pa) created [Track Companion](https://play.google.com/store/apps/details?id=com.marco97pa.trackmania) app for Android by using the Trackmania API. It is also [opensource](https://github.com/marco97pa/Track-Companion) 40 | * [Codecat](https://github.com/codecat) made a [Trackmania Website](http://trackmania.io) where, besides listing the tracks from TOTD and seasons, you can check the records from the tracks and list servers and club rooms 41 | 42 | ## Login Process and Tokens 43 | 44 | [Here](Login.md) you can check all the process of login and getting the tokens, with a explanation of what information the tokens have. 45 | 46 | ## APIs 47 | 48 | * **public-ubiservices.ubi.com** - used only to login and get a Level 0 Token 49 | * **prod-trackmania.core.nadeo.online** - used to login and get a Level 1/2 Token and responsible for overall player stuff that needs to be configured and updated (settings, mapRecords, clubs, etc.) 50 | * **live-services.trackmania.nadeo.live** - used to get seasons, track of the days, leaderboards, servers, clubcampaigns, map review. Maybe this API is different from the **prod-trackmania.core.nadeo.online** since it is responsible to save and retrieve content associated with users, like ghosts, but to avoid the overload cause by the game constantly checking the leaderboard, they decided to separate that part from the rest. 51 | * **useast1-public.aws-ubiservices.ubi.com** - used to get the integration with Uplay like login and settings 52 | * **msr-public.aws-ubiservices.ubi.com** - used to update information about the activity of a user 53 | * **akamai.net** - used to download stuff like images, logos, archive, etc. 54 | * **amazonaws.com** - where they have the files hosted like maps and stuff 55 | 56 | ## IDs 57 | 58 | There are many IDs that are used to identify things and make requests. The follow list shows that IDs and their purpose: 59 | 60 | * ProfileId - Obtained when we login to Uplay (Level 0) 61 | * AccountId - Used ingame to identify a user. Obtained within the JWT Token from Level 1 or 2 Login Process 62 | * MapId/MapUid - Used ingame to identify a map 63 | * GroupId/GroupUid - Used ingame to identify a group (***Needs more info about what is a group***) 64 | * SeasonId - Used ingame to identify a season (like the campaigns, club campaigns and track of the day) 65 | * ClubId - Used ingame to identify a club 66 | * RoomId - Used ingame to identify a room inside a club (***What type of rooms exist inside a club?***) 67 | 68 | ## Some Relevant Use Cases 69 | 70 | [Here](UseCases.md) you can check some use cases that probably you will be using and instead of trying to lookup the all documentation you can look to this file and see if you can find what you need. *Work in Progress* 71 | 72 | ## Specification 73 | 74 | You can access in more detail what endpoints exist, the information needed to send and the response received in the next links: 75 | 76 | ### By Indexs 77 | 78 | [Index By Topic](TopicIndex.md) 79 | 80 | [Overall Index](Index.md) 81 | 82 | ### By WebAPIs 83 | 84 | [Prod Trackmania API](ProdTrackmania.md) 85 | 86 | [Live Services API](LiveServices.md) 87 | 88 | [UbiServices](UbiServices.md) 89 | 90 | [msr-public and akamai.net](MSR-Akamai.md) 91 | -------------------------------------------------------------------------------- /TopicIndex.md: -------------------------------------------------------------------------------- 1 | # Index By Topic 2 | 3 | ## Login and User 4 | 5 | * [POST /v3/profiles/session](UbiServices.md#post-v3profilessession) 6 | * [POST /v2/authentication/token/ubiservices](ProdTrackmania.md#post-v2authenticationtokenubiservices) 7 | * [POST /v2/authentication/token/nadeoservices](ProdTrackmania.md#post-v2authenticationtokennadeoservices) 8 | * [POST /v2/authentication/token/basic](ProdTrackmania.md#post-v2authenticationtokenbasic) 9 | * [GET v3/profiles](UbiServices.md#get-v3profiles) 10 | 11 | ## Leaderboard 12 | 13 | ### Get Season and Maps 14 | 15 | * [GET /api/token/campaign/official](LiveServices.md#get-apitokencampaignofficial) 16 | * [GET /api/token/campaign/month](LiveServices.md#get-apitokencampaign/month) 17 | * [GET /api/token/club/campaign](LiveServices.md#get-apitokenclubcampaign) 18 | * [GET /seasons/*seasonid*](ProdTrackmania.md#get-seasonsseasonid) 19 | 20 | ### Get Scores 21 | 22 | * [GET /api/token/leaderboard/group/*groupId*/map](LiveServices.md#get-apitokenleaderboardgroupgroupIdmap) 23 | * [GET /api/token/leaderboard/group/*groupId*/](LiveServices.md#get-apitokenleaderboardgroupgroupId) 24 | * [GET /api/token/leaderboard/group/*groupId*/top](LiveServices.md#get-apitokenleaderboardgroup/groupIdtop) 25 | * [GET /api/token/leaderboard/group/*groupId*/map/*mapId*/top](LiveServices.md#get-apitokenleaderboardgroupgroupIdmapmapIdtop) 26 | * [GET /api/token/leaderboard/group/Personal_Best/map/*mapId*/top](LiveServices.md#get-apitokenleaderboardgroupPersonal_BestmapmapIdtop) 27 | * [GET /api/token/leaderboard/group/Personal_Best/map/*mapId*/surround/1/1](LiveServices.md#get-apitokenleaderboardgroupPersonal_BestmapmapIdsurround11) 28 | * [GET /api/token/leaderboard/group/*groupId*/map/*mapId*/level](LiveServices.md#get-apitokenleaderboardgroupgroupIdmapmapIdlevel) 29 | 30 | ### Get Files (Ghosts, Maps, etc.) 31 | 32 | * [GET /mapRecords](ProdTrackmania.md#get-mapRecords) 33 | * [GET /maps](ProdTrackmania.md#get-maps) 34 | * [GET /encryptedPackages/versions](ProdTrackmania.md#get-encryptedPackagesversions) 35 | 36 | 37 | ## Clubs 38 | 39 | * [GET /api/token/club/room](LiveServices.md#get-apitokenclubroom) 40 | * [GET /api/token/club/mine](LiveServices.md#get-apitokenclubmine) 41 | * [GET /api/token/club/*clubId*/member/*accountId*](LiveServices.md#get-apitokenclubclubIdmemberaccountId) 42 | * [GET /api/token/club/*clubId*/activity](LiveServices.md#get-apitokenclubclubIdactivity) 43 | * [GET /api/token/club/*clubId*/member](LiveServices.md#get-apitokenclubclubIdmember) 44 | * [GET /api/token/club/*clubId*/member/request](LiveServices.md#get-apitokenclubclubIdmemberrequest) 45 | * [GET /api/token/club/*clubId*/room/*activityId(?)*](LiveServices.md#get-apitokenclubclubIdroomactivityId) 46 | 47 | ## Skins 48 | 49 | * [GET /api/token/club/bucket/skin-upload/all](LiveServices.md#get-apitokenclubbucketskin-uploadall) 50 | 51 | ## Live Arcade 52 | 53 | * [GET /api/token/channel/officialhard](LiveServices.md#get-apitokenchannelofficialhard) 54 | * [POST /api/token/channel/officialhard/join](LiveServices.md#post-apitokenchannelofficialhardjoin) 55 | 56 | 57 | ## Trophies 58 | 59 | * [GET /trophies/settings](ProdTrackmania.md#get-trophiessettings) 60 | * [GET /accounts/*accountId*/trophies/lastYearSummary](ProdTrackmania.md#get-accountsaccountIdtrophieslastYearSummary) 61 | * [POST /api/token/leaderboard/trophy/player](LiveServices.md#post-apitokenleaderboardtrophyplayer) 62 | 63 | ## Map Review 64 | 65 | * [GET /api/token/map-review/waiting-time](LiveServices.md#get-apitokenmap-reviewwaiting-time) 66 | * [GET /api/token/map-review/connect](LiveServices.md#get-apitokenmap-reviewconnect) 67 | 68 | 69 | ## Game Configuration 70 | 71 | * [GET /client/config](ProdTrackmania.md#get-clientconfig) 72 | * [PUT /waitingQueue/*some id*](ProdTrackmania.md#put-waitingQueuesome-id) 73 | * [PUT /accounts/*accountId*/presence](ProdTrackmania.md#put-accountsaccountIdpresence) 74 | * [GET /accounts/*accountId*/policies/global/rules](ProdTrackmania.md#get-accountsaccountIdpoliciesglobalrules) 75 | * [GET /accounts/*accountId*/client/config](ProdTrackmania.md#get-accountsaccountIdclientconfig) 76 | * [GET /accounts/*accountId*/client/signature](ProdTrackmania.md#get-accountsaccountIdclientsignature) 77 | * [GET /accounts/*accountId*/encryptedPackage/key](ProdTrackmania.md#get-accountsaccountIdencryptedPackagekey) 78 | * [GET /client/updaters/current](ProdTrackmania.md#get-clientupdaterscurrent) 79 | * [GET /accounts/*accountId*/client/urls](ProdTrackmania.md#get-accountsaccountIdclienturls) 80 | * [GET /accounts/*accountId*/client/plugins](ProdTrackmania.md#get-accountsaccountIdclientplugins) 81 | * [GET /accounts/*accountId*/zone](ProdTrackmania.md#get-accountsaccountIdzone) 82 | 83 | ## Zones 84 | 85 | * [GET /zones](ProdTrackmania.md#get-zones) 86 | 87 | ## Misc 88 | 89 | * [GET /encryptedPackages/versions](ProdTrackmania.md#get-encryptedPackagesversions) 90 | * [POST /mapRecords](ProdTrackmania.md#post-mapRecords) 91 | * [GET /servers/*someId*](ProdTrackmania.md#get-serverssomeId) 92 | * [GET /api/token/club/follower/map/*mapId*](LiveServices.md#get-apitokenclubfollowermapmapId) 93 | * [GET /api/token/club/player-vip/map/*mapId*](LiveServices.md#get-apitokenclubplayer-vipmapmapId) 94 | * [GET /v1/applications/86263886-327a-4328-ac69-527f0d20a237/parameters](UbiServices.md#get-v1applications86263886-327a-4328-ac69-527f0d20a237parameters) 95 | * [PUT /v1/profiles/me/populations/data](UbiServices.md#put-v1profilesmepopulationsdata) 96 | * [GET /v1/spaces/*profileId*/parameters](UbiServices.md#get-v1spacesprofileIdparameters) 97 | * [GET /v1/spaces/*profileId*/configs/primarystore](UbiServices.md#get-v1spacesprofileIdconfigsprimarystore) 98 | * [GET /v4/spaces/*profileId*/configs/events](MSR-Akamai.md#get-v4spacesprofileIdconfigsevents) 99 | * [POST /v3/profiles/me/events](MSR-Akamai.md#post-v3profilesmeevents) 100 | * [GET /club/*clubId*/activity/*nameContent*](MSR-Akamai.md#get-clubclubidactivitynamecontent-exclub3118activity658045f18c059062cfpngupdatetimestamp1595457628png) 101 | -------------------------------------------------------------------------------- /UbiServices.md: -------------------------------------------------------------------------------- 1 | # Routes useast1-public.aws-ubiservices.ubi.com 2 | 3 | ## POST /v3/profiles/session 4 | 5 | ### Use: 6 | 7 | Login to the ubiservices.ubi.com (the ticket obtained in the endPoint is used in the others of this API) 8 | 9 | ### Request: 10 | 11 | #### Headers (**probably only the authorization and the Ubi-AppId is necessary**) 12 | 13 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 14 | * Accept: \*/\* 15 | * Authorization: uplaypc_v1 t=***Idk where this token came from*** 16 | * Content-Type: application/json 17 | * ubi-appbuildid: 202007232022 18 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 19 | * Ubi-localeCode: xx-PT 20 | * Ubi-Populations: US_EMPTY_VALUE 21 | * Content-Length: 2 22 | 23 | #### Body: {} 24 | 25 | ### Response: 26 | 27 | #### Headers: 28 | 29 | * Content-Type: application/json; charset=utf-8 30 | * Expires: -1 31 | * Ubi-Forwarded-By: ue1-p-us-public-nginx-0b4fb579f26ee4405 32 | * Ubi-TransactionId: cc535306-ca27-4bad-b0d6-394945896335 33 | * Strict-Transport-Security: max-age=63072000 34 | * X-Frame-Options: DENY 35 | * X-Content-Type-Options: nosniff 36 | 37 | #### Body: 38 | 39 | * ```json 40 | {"platformType":"uplay","ticket":"*ticket*","twoFactorAuthenticationTicket":null,"profileId":"*profileId/userId*","userId":"","nameOnPlatform":"*username*","environment":"Prod","expiration":"2020-07-24T21:15:48.7337442Z","spaceId":"*spaceId","clientIp":"*ip*","clientIpCountry":"*countrycode*","serverTime":"2020-07-24T18:15:48.7393476Z","sessionId":"*sessionid*","sessionKey":"*sessionKey*","rememberMeTicket":null} 41 | ``` 42 | 43 | * platformType, ticket, twoFactorAuthenticationTicket, profileId, userId, nameOnPlatform, environment, expriation, spaceId, clientIp, clientIpCountry, serverTime, sessionId, sessionKey, rememberMeTicket 44 | 45 | ## GET /v1/applications/86263886-327a-4328-ac69-527f0d20a237/parameters 46 | 47 | *86263886-327a-4328-ac69-527f0d20a237 = Trackmania 2020 AppId* 48 | 49 | ### Use: 50 | 51 | ***Idk, but since the URL contains the Trackmania 2020 App Id, it's probably related to endpoints the game should use to work*** 52 | 53 | ### Request: 54 | 55 | #### Headers: 56 | 57 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 58 | * Accept: \*/\* 59 | * Authorization: Ubi_v1 t=*ticket value from POST /v3/profiles/session* 60 | * Content-Type: application/json 61 | * ubi-appbuildid: 202007232022 62 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 63 | * Ubi-localeCode: xx-PT 64 | * Ubi-Populations: US_EMPTY_VALUE 65 | * Ubi-SessionId: 5090d904-ec68-47bd-9013-db82432ff5dc 66 | 67 | #### Params: 68 | 69 | * parameterGroups=us-staging,us-sdkClientUrlsPlaceholders,us-sdkClientClub,us-sdkClientFeaturesSwitches,us-sdkClientLogin,us-sdkClientUrls,us-sdkClientChina 70 | 71 | ### Response: 72 | 73 | #### Headers: 74 | 75 | * Content-Type: application/json; charset=utf-8 76 | * Expires: -1 77 | * X-AspNet-Version: 4.0.30319 78 | * X-Powered-By: ASP.NET 79 | * Ubi-Forwarded-By: ue1-p-us-public-nginx-0b4fb579f26ee4405 80 | * Ubi-TransactionId: eb498bf8-ee9a-4b07-90dd-45927fa1459f 81 | * Strict-Transport-Security: max-age=63072000 82 | * X-Frame-Options: DENY 83 | * X-Content-Type-Options: nosniff 84 | 85 | #### Body: 86 | 87 | * ```json 88 | {"parameters":{"us-staging":{"fields":{"spaceId":""},"relatedPopulation":null},"us-sdkClientUrlsPlaceholders":{"fields":{"baseurl_aws":{"Standard":"https://{env}public-ubiservices.ubi.com","China":"https://public-ubiservices.ubisoft.cn","China_GAAP":"https://gaap.ubiservices.ubi.com:12000"},"baseurl_msr":{"Standard":"https://msr-{env}public-ubiservices.ubi.com","China":"https://public-ubiservices.ubisoft.cn","China_GAAP":"https://gaap.ubiservices.ubi.com:12000"},"baseurl_ws":{"Standard":"wss://{env}public-ws-ubiservices.ubi.com","China":"wss://gaap.ubiservices.ubi.com:16000","China_GAAP":"wss://gaap.ubiservices.ubi.com:16000"}},"relatedPopulation":null},"us-sdkClientUrls":{"fields":{"populations":"https://{env}public-ubiservices.ubi.com/{version}/profiles/me/populations"},"relatedPopulation":null},"us-sdkClientLogin":{"fields":{"populationHttpRequestOptimizationEnabled":true,"populationHttpRequestOptimizationRetryCount":0,"populationHttpRequestOptimizationRetryTimeoutIntervalMsec":5000,"populationHttpRequestOptimizationRetryTimeoutIncrementMsec":1000},"relatedPopulation":null},"us-sdkClientFeaturesSwitches":{"fields":{"populationsAutomaticUpdate":true},"relatedPopulation":null},"us-sdkClientClub":{"fields":{"dynamicPanelUrl":"https://{env}public-ubiservices.ubi.com/v1/profiles/{profileId}/club/dynamicPanel/MyProfile.png?spaceId={spaceId}&noRedirect=true","ps4ClubWebsite":"https://static8.cdn.ubi.com/u/sites/uplay/index.html","ps4ClubWebsiteArguments":"url=/games/{deepLink}&spaceId={spaceId}&applicationId={applicationId}&context={context}&env={clubEnvName}&genomeid={applicationId}&actioncompleted={actionCompletedList}&ussdkversion={usSdkVersionName}&debug={debug}{geometry}&ticket={ticket}&profileid={profileId}","ps4PsnoLaunchPath":"psno://localhost/?response_type=code&client_id=171ca84a-371e-412b-a807-6531f3f1e454&scope=psn%3As2s&redirect_uri={ps4ClubWebsiteUrlEncoded}&state={ps4ClubWebsiteArgumentsPsnoEncoded}","xoneLaunchPath":"Ms-xbl-55C5EE27://default?url=/games/{deepLink}&context={context}&titleid={gameTitleId}&env={clubEnvName}&genomeid={applicationId}&actioncompleted={actionCompletedList}&debug={debug}&spaceId={spaceId}&applicationId={applicationId}","switchClubWebsiteUrl":"https://static8.cdn.ubi.com/u/sites/UbisoftClub/NintendoSwitch/index.html?url=/games/{deepLink}&ussdkversion={usSdkVersionName}&env={clubEnvName}&actioncompleted={actionCompletedList}&forceLang={forceLang}&profileId={profileId}&ticket={ticket}&context={context}&debug={debug}&spaceId={spaceId}&applicationId={applicationId}","stadiaClubWebsiteUrl":"https://static8.cdn.ubi.com/u/sites/UbisoftClub/Stadia/index.html?url=/games/{deepLink}&spaceId={spaceId}&applicationId={applicationId}&profileId={profileId}&env={env}&displayMode={displayMode}&locale={locale}&actioncompleted={actionCompletedList}&jotunVersion={jotunVersion}&jotunBinaryVersion={jotunBinaryVersion}&ticket={ticket}"},"relatedPopulation":null},"us-sdkClientChina":{"fields":{"tLogApplicationId":"","tLogApplicationKey":"","tLogApplicationName":"","websocketHost":"public-ws-ubiservices.ubi.com"},"relatedPopulation":null}}} 89 | ``` 90 | 91 | ## PUT /v1/profiles/me/populations/data 92 | 93 | ### Use: 94 | 95 | ***Idk*** 96 | 97 | ### Request: 98 | 99 | #### Headers: 100 | 101 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 102 | * Accept: \*/\* 103 | * Authorization: Ubi_v1 t=*ticket value from POST /v3/profiles/session* 104 | * Content-Type: application/json 105 | * ubi-appbuildid: 202007232022 106 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 107 | * Ubi-localeCode: xx-PT 108 | * Ubi-Populations: US_EMPTY_VALUE 109 | * Ubi-SessionId: 5090d904-ec68-47bd-9013-db82432ff5dc 110 | * Content-Length: 125 111 | * Expect: 100-continue 112 | 113 | #### Body: 114 | 115 | * ```json 116 | {"spaceId":"*spaceId/accountId(?)*","data":{"US_SDK_APPLICATION_BUILD_ID":"202007232022","US_SDK_DURABLES":[]}} 117 | ``` 118 | 119 | ### Response: 120 | 121 | #### Headers: 122 | 123 | * Content-Type: application/json; charset=utf-8 124 | * Expires: -1 125 | * X-AspNet-Version: 4.0.30319 126 | * X-Powered-By: ASP.NET 127 | * Ubi-Forwarded-By: ue1-p-us-public-nginx-0b4fb579f26ee4405 128 | * Ubi-TransactionId: bb449328-e7bd-4f1f-ac80-2f3471f2a8f2 129 | * Strict-Transport-Security: max-age=63072000 130 | * X-Frame-Options: DENY 131 | * X-Content-Type-Options: nosniff 132 | 133 | #### Body: 134 | 135 | * ```json 136 | {"populations":[]} 137 | ``` 138 | 139 | ## GET /v1/spaces/*profileId*/parameters 140 | 141 | ### Use: 142 | 143 | ***Idk, seems to have endPoints and some configuration returned*** 144 | 145 | ### Request: 146 | 147 | #### Headers: 148 | 149 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 150 | * Accept: \*/\* 151 | * Authorization: Ubi_v1 t=*ticket value from POST /v3/profiles/session* 152 | * Content-Type: application/json 153 | * ubi-appbuildid: 202007232022 154 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 155 | * Ubi-localeCode: xx-PT 156 | * Ubi-Populations: US_EMPTY_VALUE 157 | * Ubi-SessionId: *sessionId* 158 | 159 | #### Params: 160 | 161 | * parameterGroups=us-sdkClientFeaturesSwitches,us-sdkClientRemoteLogsGame,us-sdkClientSettings,us-sdkClientSettingsHttpGame,us-sdkClientSettingsHttpInternal,us-sdkClientUrls,us-sdkClientRemoteLogsInternal,us-sdkClientNotificationsGame,us-sdkClientNotificationsInternal,us-sdkClientNotificationsSpaceIds,us-override,us-sdkClientSettingsCacheTTL,us-sdkClientSettingsSecondaryStoreSync,us-sdkClientStorm,us-sdkClientSettingsWebSocketGame,us-sdkClientSettingsWebSocketInternal,NadeoServicesParameters,NadeoServicesParameters_5595,BetaParameters 162 | 163 | ### Response: 164 | 165 | #### Headers: 166 | 167 | * Content-Type: application/json; charset=utf-8 168 | * Expires: -1 169 | * X-AspNet-Version: 4.0.30319 170 | * X-Powered-By: ASP.NET 171 | * Ubi-Forwarded-By: ue1-p-us-public-nginx-0b4fb579f26ee4405 172 | * Ubi-TransactionId: 5dccdf12-2c05-4365-9b3d-d6e8fda003b6 173 | * Strict-Transport-Security: max-age=63072000 174 | * X-Frame-Options: DENY 175 | * X-Content-Type-Options: nosniff 176 | 177 | #### Body: 178 | 179 | * ```json 180 | {"parameters":{"NadeoServicesParameters_5595":{"fields":{"masterserver_init_url":"https://prod.trackmania.core.nadeo.online/api/routes"},"relatedPopulation":null},"NadeoServicesParameters":{"fields":{"masterserver_init_url":"https://beta.trackmania.core.nadeo.online/api/routes"},"relatedPopulation":null},"us-sdkClientUrls":{"fields":{"allConnections":"https://{env}public-ubiservices.ubi.com/{version}/profiles/connections","allProfilesApplications":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/applications","allProfilesEntities":"https://{env}public-ubiservices.ubi.com/{version}/profiles/entities","allProfilesStats":"https://{env}public-ubiservices.ubi.com/{version}/profiles/stats","allSpacesEntities":"https://{env}public-ubiservices.ubi.com/{version}/spaces/entities","allSpacesItems":"https://{env}public-ubiservices.ubi.com/{version}/spaces/items","allSpacesOffers":"https://{env}public-ubiservices.ubi.com/{version}/spaces/offers","applications":"https://{env}public-ubiservices.ubi.com/{version}/applications/{applicationId}/configuration","applicationsMetadata":"https://{env}public-ubiservices.ubi.com/{version}/applications","applicationsParameters":"https://{env}public-ubiservices.ubi.com/{version}/applications/{applicationId}/parameters","challenge":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/challenges","challengeProgression":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/challenges/progressions","configsEvents":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/events","connections":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/connections","events":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/events","friends":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/friends","gamesPlayed":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/gamesplayed","moderation":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/moderation/{text}","moderationPOST":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/moderation","news":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/news","policies":"https://{env}public-ubiservices.ubi.com/{version}/policies","profiles":"https://{env}public-ubiservices.ubi.com/{version}/profiles","profilesActions":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/club/actions","profilesApplications":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/applications","profilesChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/club/challenges","profilesEntities":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/entities","profilesExternal":"https://{env}public-ubiservices.ubi.com/{version}/profiles/external","profilesInventory":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/inventory","profilesInventoryExpiredDetails":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/inventory/expiredDetails","profilesInventoryInstances":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/inventory/instances","profilesInventoryInstancesTransactions":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/inventory/instances/transactions","profilesInventoryPrimarystore":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/inventory/primarystore","profilesInventoryTransactions":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/inventory/transactions","profilesLeaderboard":"https://{env}public-ubiservices.ubi.com/{version}/profiles/ranks","profilesMeBattlepassesSeasons":"https://{env}public-ubiservices.ubi.com/{version}/profiles/me/battlepasses/seasons","profilesMeCommunityChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/club/communityChallenges","profilesMeEvents":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/events","profilesMeInventoryPrimarystore":"https://{env}public-ubiservices.ubi.com/{version}/profiles/me/inventory/primarystore","profilesMeLeaderboard":"https://{env}public-ubiservices.ubi.com/{version}/profiles/me/ranks","profilesNotifications":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/notifications","profilesNotificationsBatch":"https://{env}public-ubiservices.ubi.com/{version}/profiles/notifications","profilesProfileChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/me/club/playerchallenges","profilesPreciseMatchmakingClient":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/matches/precise/clientstate","profilesPreciseMatchmakingMatch":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/matches/precise/matchstate","profilesRewards":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/club/rewards","profilesSeasonChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/club/seasonchallenges?spaceId={spaceId}","profilesStats":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/stats","profilesStatsCard":"https://{env}public-ubiservices.ubi.com/{version}/profiles/statscard","profilesUgcPhotos":"https://{env}public-ubiservices.ubi.com/{version}/profiles/ugc/photos","profilesUgcPhotosOwn":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/ugc/photos","profilesUgcViews":"https://{env}public-ubiservices.ubi.com/{version}/profiles/ugc/{contentId}/views","profilesUgcFavorites":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/ugc/favorites","profilesUgcRatings":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/ugc/ratings","profilesUgcExternalVideos":"https://{env}public-ubiservices.ubi.com/{version}/profiles/ugc/externalvideos","profilesUgcUpdateFavorite":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/ugc/{contentId}/favorites","profilesUgcUpdateRating":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/ugc/{contentId}/ratings","recommendations":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/recommendations","remoteLogs":"https://{env}public-ubiservices.ubi.com/{version}/profiles/me/remotelog","sandboxes":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/sandboxes","spacesActions":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/actions","spacesBattlepasses":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/battlepasses","spacesBattlepassesSeasons":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/battlepasses/seasons","spacesChallengepools":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/club/challengepools","spacesChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/club/challenges","spacesCommunityChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/club/communityChallenges","spacesConfigsPrimarystore":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/primarystore","spacesConfigsSsiAttributes":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/secondarystore/instances/attributes","spacesConfigsSsiListsOfAttributes":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/secondarystore/instances/listsOfAttributes","spacesConfigsSsiRules":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/secondarystore/instances/rules","spacesConfigsUgc":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/ugc","spacesEntities":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/entities","spacesItems":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/items","spacesLeaderboard":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/leaderboards","spacesNews":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/news","spacesOffers":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/offers","spacesParameters":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/parameters","spacesRewards":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/rewards","spacesSeasonChallenges":"https://msr-{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/club/seasonchallenges","spacesStats":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/communitystats","spacesStatsCard":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/communitystatscard","sessions":"https://{env}public-ubiservices.ubi.com/{version}/profiles/sessions","users":"https://{env}public-ubiservices.ubi.com/{version}/users","tLog":"https://tglog.datamore.qq.com/{appId}/report/","voicechatTokenVivox":"https://{env}public-ubiservices.ubi.com/{version}/profiles/{profileId}/voicechattoken/vivox","voicechatConfigVivox":"https://{env}public-ubiservices.ubi.com/{version}/spaces/{spaceId}/configs/voicechat/vivox","websocketNotifications":"wss://{env}public-ws-ubiservices.ubi.com/{version}/websocket","websocketServer":"wss://{env}public-ws-ubiservices.ubi.com"},"relatedPopulation":null},"us-sdkClientStorm":{"fields":{"detectConfig":"EnableDebug=false;ValidateDetect=true","detectProvisioningUrl":"https://ncsa-storm.ubi.com/v1/natdetect","traversalProvisioningUrl":"https://ncsa-storm.ubi.com/v1/nattraversal","routerProvisioningUrl":"https://apac-storm.ubi.com/v1/router;https://emea-storm.ubi.com/v1/router;https://ncsa-storm.ubi.com/v1/router;https://ap-southeast-2-storm.ubi.com/v1/router","matchmakingSandboxName":"SM_PC_LNCH_A","matchmakingSandboxSpaceId":"*matchmakingSandboxSpaceId*"},"relatedPopulation":null},"us-sdkClientSettingsWebSocketInternal":{"fields":{"maxCount":50,"connectionPingIntervalSec":30,"retryIncrementFactorMsec":5000,"retryRandomDelayMsec":5000,"retryInitialDelayMsec":5000,"timeoutInitialDelayMsec":30000,"timeoutIncrementFactorMsec":5000},"relatedPopulation":null},"us-sdkClientSettingsWebSocketGame":{"fields":{"connectionPingIntervalSec":30,"retryIncrementFactorMsec":5000,"retryRandomDelayMsec":5000,"retryInitialDelayMsec":5000,"timeoutInitialDelayMsec":30000,"timeoutIncrementFactorMsec":5000},"relatedPopulation":null},"us-sdkClientSettingsSecondaryStoreSync":{"fields":{"maxCount":10,"retryInitialDelayMsec":5000,"retryIncrementFactorMsec":5000,"retryRandomDelayMsec":5000},"relatedPopulation":null},"us-sdkClientSettingsHttpInternal":{"fields":{"maxCount":3,"retryInitialDelayMsec":5000,"retryIncrementFactorMsec":5000,"retryRandomDelayMsec":5000,"timeoutInitialDelayMsec":30000,"timeoutIncrementFactorMsec":5000},"relatedPopulation":null},"us-sdkClientSettingsHttpGame":{"fields":{"maxCount":3,"retryInitialDelayMsec":5000,"retryIncrementFactorMsec":5000,"retryRandomDelayMsec":5000,"timeoutInitialDelayMsec":30000,"timeoutIncrementFactorMsec":5000},"relatedPopulation":null},"us-sdkClientSettingsCacheTTL":{"fields":{"defaultSec":120,"profilesNewsSec":900,"spacesNewsSec":900,"profilesActionsSec":120,"profilesChallengesSec":120,"profilesRewardsSec":120,"friendsListSec":1800,"ssiAttributesAllSec":86400,"ssiListsOfAttributesAllSec":86400,"ssiRulesAllSec":86400,"profilesChallengesStatusSeasonSec":60,"challengesDefinitionSeasonSec":180,"battlepassSeasonProgressionSec":60},"relatedPopulation":null},"us-sdkClientSettings":{"fields":{"popEventsTimeoutMsec":5000,"primaryStoreSyncDelayMsec":250,"minBackgroundDurationForInventoryInvalidationMsec":5000,"notificationTypesUpdateRandomDelayMsec":3000,"xboxOneResumeFromSuspendedDelayMsec":5000,"createSessionRestPeriodMSec":3000,"createSessionRestRandomMSec":5000,"xboxOneCloseWebsocketOnSuspendingMode":"All","waitRemoteLogCompletionOnDeleteSession":false,"createSessionRestPeriodAfterConcurrentConnectDetectedMSec":60000},"relatedPopulation":null},"us-sdkClientRemoteLogsInternal":{"fields":{"maxTextLength":32768,"applicationUsed":"None","applicationInformation":"None","async":"None","authentication":"None","battlepass":"Warning","challenge":"None","club":"None","configuration":"None","connection":"None","core":"None","coreNotification":"None","entity":"None","event":"None","friend":"None","gamesPlayed":"None","http":"None","httpEngine":"None","job":"None","leaderboard":"None","localization":"None","matchmaking":"None","mobileExtension":"None","moderation":"Warning","news":"None","notification":"None","overlay":"Warning","parameters":"Warning","population":"None","primaryStore":"None","profile":"None","recommendations":"None","remoteLog":"None","scheduler":"None","secondaryStore":"None","stats":"None","task":"None","test":"None","tLog":"Warning","ugc":"Warning","user":"None","userContent":"None","voicechat":"None","websocket":"None"},"relatedPopulation":null},"us-sdkClientRemoteLogsGame":{"fields":{"url":"","maxTextLength":32768,"uncategorized":"None"},"relatedPopulation":null},"us-sdkClientNotificationsSpaceIds":{"fields":{"FriendsService":"*friendServiceId*"},"relatedPopulation":null},"us-sdkClientNotificationsInternal":{"fields":{"BATTLEPASS_TIERS_BANKED":true,"CHALLENGES_PROGRESSION_COMPLETED":true,"CHALLENGES_REWARDS_BANKED":true,"CLUB_REWARD_PURCHASED":true,"CLUB_ACTION_COMPLETED":true,"CLUB_CHALLENGE_THRESHOLD_REACHED":true,"CLUB_CHALLENGE_PARTICIPATION":true,"CLUB_CHALLENGE_BANKED":true,"CLUB_BADGE_ACQUIRED":true,"CLUB_CHALLENGE_COMPLETED":true,"FRIENDS_RELATIONSHIP_UPDATE":true,"SSI_INSTANCES_UPDATE":true,"US_CLIENT_SECONDARY_STORE_UPDATE":true,"US_APP_PARAMS_FULL_UPDATE":true,"US_APP_PARAMS_GROUP_UPDATE":true,"US_NOTIFICATION_MAINTENANCE":true,"US_SPACE_PARAMS_FULL_UPDATE":true,"US_SPACE_PARAMS_GROUP_UPDATE":true},"relatedPopulation":null},"us-sdkClientNotificationsGame":{"fields":{"additionalSpaces":[]},"relatedPopulation":null},"us-sdkClientFeaturesSwitches":{"fields":{"applicationUsed":true,"applicationInformation":true,"battlepass":true,"challenge":false,"clubApplication":true,"clubDynamicPanel":true,"clubService":true,"createSession":true,"entitiesProfile":true,"entitiesSpace":true,"event":true,"extendSession":true,"firstPartyAccessToMultiplayerInformation":true,"friendsLookup":true,"friendsRequest":true,"friendsUplayProfile":false,"gamesPlayed":true,"httpClient":true,"leaderboardMe":true,"leaderboardProfiles":true,"leaderboardSpaces":true,"matchmaking":true,"mobileExtensionProfilesExternal":true,"mobileExtensionUsersManagement":true,"moderation":true,"news":true,"notificationDynamicUpdate":true,"notificationRequestConnections":true,"notificationSend":true,"notificationSendBatch":true,"notificationSendNoBroker":true,"notificationWebsocket":true,"notificationRemoteLogReceivedData":false,"populations":true,"populationsAutomaticUpdate":true,"primaryStoreCatalogGetGameMediaType":false,"primarySecondaryStoreForceSyncAtLogin":true,"primaryStore":true,"primaryStoreAutomaticFetch":true,"primaryStoreSendEvent":true,"profiles":true,"recommendations":true,"secondaryStore":true,"secondaryStoreInstantiation":false,"secondaryStoreTransactions":true,"sessionTicket":true,"stats":true,"syncOnResumeToForegroundForNintendoSwitch":false,"tlog":true,"users":true,"ugc":false,"usersCreateAndLink":true,"usersLegalOptins":true,"voicechat":true,"webSocketClient":true},"relatedPopulation":null}}} 181 | ``` 182 | 183 | ## GET /v1/spaces/*profileId*/configs/primarystore 184 | 185 | ### Use: 186 | 187 | ***Idk*** 188 | 189 | ### Request: 190 | 191 | #### Headers: 192 | 193 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 194 | * Accept: \*/\* 195 | * Authorization: Ubi_v1 t=*ticket value from POST /v3/profiles/session* 196 | * Content-Type: application/json 197 | * ubi-appbuildid: 202007232022 198 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 199 | * Ubi-localeCode: *localCode* 200 | * Ubi-Populations: US_EMPTY_VALUE 201 | * Ubi-SessionId: *sessionId* 202 | 203 | ### Response: 204 | 205 | #### Headers: 206 | 207 | * Ubi-Forwarded-By: ue1-p-us-public-nginx-0b4fb579f26ee4405 208 | * Ubi-TransactionId: 7f2c7738-1f1c-4bd6-aff8-c0611ea11c69 209 | * Strict-Transport-Security: max-age=63072000 210 | * X-Frame-Options: DENY 211 | * X-Content-Type-Options: nosniff 212 | 213 | #### Body: 214 | 215 | * ```json 216 | {"mappings":[]} 217 | ``` 218 | 219 | ## GET v3/profiles 220 | 221 | ### Use: 222 | 223 | Get more info about the users 224 | 225 | ### Request: 226 | 227 | #### Headers: 228 | 229 | * User-Agent: UbiServices_SDK_2019.Release.13_PC64_ansi_static_cn 230 | * Accept: \*/\* 231 | * Authorization: Ubi_v1 t=*ticket value from POST /v3/profiles/session* 232 | * Content-Type: application/json 233 | * ubi-appbuildid: 202007232022 234 | * Ubi-AppId: 86263886-327a-4328-ac69-527f0d20a237 235 | * Ubi-localeCode: *localCode* 236 | * Ubi-Populations: US_EMPTY_VALUE 237 | * Ubi-SessionId: *sessionId* 238 | 239 | #### Params: 240 | 241 | * profileId=*profileIdsListSeparatedByComma* 242 | 243 | ### Response: 244 | 245 | #### Headers: 246 | 247 | * Content-Type: application/json; charset=utf-8 248 | * Expires: -1 249 | * Ubi-Forwarded-By: ue1-p-us-public-nginx-0b4fb579f26ee4405 250 | * Ubi-TransactionId: 21519912-1041-41c2-9532-1525e532dee6 251 | * Strict-Transport-Security: max-age=63072000 252 | * X-Frame-Options: DENY 253 | * X-Content-Type-Options: nosniff 254 | 255 | #### Body: 256 | 257 | * ```json 258 | {"profiles":[{"profileId":"*profileId/userId/idOnPlataform*","userId":"*profileId/userId/idOnPlataform*","platformType":"uplay","idOnPlatform":"*profileId/userId/idOnPlataform*","nameOnPlatform":"*name*"}]} 259 | ``` -------------------------------------------------------------------------------- /UseCases.md: -------------------------------------------------------------------------------- 1 | # Some Relevant Use Cases 2 | 3 | ## Obtain an username from an AccountID/ProfileID 4 | 5 | **Steps: (if you have the ProfileID skip to step 2)** 6 | 7 | 1. With the AccountID make a request to GET /webidentities/?accountIdList= from ProdTrackmania API and save the ProfileID 8 | 2. With the ProfileID make a request to GET v3/profiles?profileId= from the UbiServices API and save the username. 9 | 10 | ## Download a Record and Play It On Trackmania 11 | 12 | *Thanks to [Breeku](https://github.com/breeku/) from showing me how I can play a ghost file on the Trackmania 2020. Check my question [here](https://www.reddit.com/r/TrackMania/comments/htz49s/convert_a_ghost_gbx_to_a_replay_gbx_to_be_able_to/) and his method [here](https://www.reddit.com/r/TrackMania/comments/i51q98/download_and_view_wr_ghosts_in_replay_editor/)* 13 | 14 | 1. Make a request to GET /mapRecords/?accountIdList= with the accountId, seasonId and mapIdList that you want to get. 15 | 2. Grab the URL Link and download the file 16 | 3. Change the extension to .gbx (the file will not have any extension when you download) 17 | 4. Put on the Replays folder of your Trackmania Folder (normally located on your Documents Folder) 18 | 5. Start the Trackmania 2020, go the Create Section -> Editor Replay -> **Select YOUR REPLAY ON THE SAME MAP** -> Edit 19 | 6. Bottom Part of the editor with a clock symbol, you can read "Import Ghost", select and open the file you download 20 | 7. Done! -------------------------------------------------------------------------------- /loginTrackmania.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/The-Firexx/trackmania2020apidocumentation/dd78c9430f62f52b8fedb96984860ee9bc1e99fc/loginTrackmania.png --------------------------------------------------------------------------------