@yaelouuu/fortnite-api 8.1.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -108,16 +108,58 @@ const duoLeaderboard = await client.tournaments.getLeaderboardV2(
108
108
  ```
109
109
 
110
110
  #### Tournament Tracker
111
- Track player participation history:
111
+ Track player participation history. Returns human-readable event names plus the official window `beginTime` / `endTime`:
112
112
 
113
113
  ```typescript
114
114
  const tracker = await client.tournaments.getTracker(
115
115
  "accountId",
116
116
  "fortniteToken"
117
117
  );
118
- // Returns: All tournaments the player has participated in
118
+ // Returns: tournaments the player took part in over the last 180 days.
119
+ // The first call for an account queues a backfill of a few minutes: while
120
+ // tracker.history.complete is false the count is a lower bound — re-poll.
119
121
  ```
120
122
 
123
+ #### Player Result in One Tournament — **no user token**
124
+ Final placement, points, team and every match played, without the OAuth flow:
125
+
126
+ ```typescript
127
+ const result = await client.tournaments.getPlayerWindowMatches(
128
+ "epicgames_S41_CashCup_DuosZB_OCE",
129
+ "S41_CashCup_DuosZB_Event1Round1_OCE",
130
+ "b6d0db0cefd74ccda92c111e7230ac33",
131
+ { rankHint: 1 } // optional, but turns a page scan into a single fetch
132
+ );
133
+
134
+ console.log(result.rank); // 1
135
+ console.log(result.pointsEarned); // 704
136
+ console.log(result.teamAccountIds.length); // 2 -> team size
137
+ console.log(result.matches[0].trackedStats.PLACEMENT_STAT_INDEX);
138
+ ```
139
+
140
+ #### Recent Tournament Sessions — **token required**
141
+ A player's recent tournament sessions, grouped by event window. Epic keeps roughly the last **36 hours** of this data, so it is not a full history (use the tracker for 180 days), and private custom-key matches never appear. Epic only serves it to the player it belongs to, so a token-less call returns `403`:
142
+
143
+ ```typescript
144
+ const matches = await client.tournaments.getPlayerMatches(
145
+ "accountId",
146
+ "fortniteToken",
147
+ { after: "2026-01-01" }
148
+ );
149
+ ```
150
+
151
+ #### Current Match of a Consenting Player — **token required, Custom plan**
152
+ The match a player is in right now, any mode — Battle Royale, Reload, Ranked or a custom-key scrim hosted by anyone. The only route to non-tournament matches: Epic has no match-history listing. `sessionId` is the replay match ID; `playlist` lets you filter for scrims before parsing.
153
+
154
+ ```typescript
155
+ const session = await client.tournaments.getPlayerSession("accountId", "fortniteToken");
156
+ if (session.inMatch && session.playlist === "playlist_showdown_cts_solo") {
157
+ console.log(session.sessionId); // parse it with the replay endpoints once the match has ended
158
+ }
159
+ ```
160
+
161
+ Read before building on it: the token must be that player's **own** (verified — any other account's token is `403`); Fortnite kills every other session of an account when the game launches, so mint it from stored device auth (`/oauth/link`, then `/oauth/refresh-device` on `401`); the response is cached 10 s per account and Epic's party state lags the real match by about 1–2 minutes; the custom key is never returned (`hasCustomKey` only) and teammates appear as account ids only.
162
+
121
163
  #### Check Tournament Eligibility
122
164
  Verify if a player meets requirements for major tournaments (e.g., 14 tournaments in 180 days):
123
165
 
@@ -151,6 +193,57 @@ const events = await client.tournaments.download(
151
193
 
152
194
  ---
153
195
 
196
+ ### Power Rankings - **NEW**
197
+
198
+ Epic's own competitive Power Rankings ladder — the same figure shown in the in-game Compete tab and on Fortnite's competitive site. Read live from Epic's events service; nothing here is computed by the API or taken from a third-party tracker.
199
+
200
+ Top 10,000 players (100 pages x 100), chapter-scoped (e.g. `"C7 Power Rankings"`). Epic publishes the ladder as a periodic snapshot — every entry on every page carries the same `sessionHistory[0].endTime`, which is that snapshot's date. The API re-fetches Epic hourly and rebuilds the search index every 2 hours.
201
+
202
+ #### Leaderboard
203
+
204
+ ```typescript
205
+ const board = await client.powerRankings.getLeaderboard({ page: 0 });
206
+
207
+ const top = board.entries[0];
208
+ console.log(top.rank); // 1
209
+ console.log(top.pointsEarned); // PR score
210
+ console.log(top.sessionHistory[0].trackedStats); // PR, countingEvents (max 20), peakPR, deltaPR, peakPerf
211
+ console.log(top.teamAccountDisplayNames); // display names, already resolved
212
+ ```
213
+
214
+ Pass a token **and** the matching `accountId` to also get that player's own entry as `playerEntry`, even when they fall outside the requested page:
215
+
216
+ ```typescript
217
+ const board = await client.powerRankings.getLeaderboard(
218
+ { page: 0, accountId: "your-account-id" },
219
+ "fortniteToken"
220
+ );
221
+ console.log(board.playerEntry); // null when unranked
222
+ ```
223
+
224
+ #### Look up one player — **no token**
225
+
226
+ ```typescript
227
+ const found = await client.powerRankings.search("scroll", 3);
228
+ console.log(found.results[0]); // { accountId, displayName, rank, score, countingEvents, peakPr, deltaPr }
229
+
230
+ const archived = await client.powerRankings.getFromArchive("accountId");
231
+ console.log(archived.rank, archived.bestRank, archived.seasonLabel, archived.lastUpdated);
232
+ ```
233
+
234
+ #### Look up one player — **token required**
235
+
236
+ `getPlayer()` needs the `x-fortnite-token` of the player being looked up. Epic rejects the underlying `teamAccountIds` filter under service auth, so a token-less call returns **400** for every account, including accounts inside the top 10,000. With the token it resolves players ranked beyond the top 10,000 as well.
237
+
238
+ ```typescript
239
+ const entry = await client.powerRankings.getPlayer("displayNameOrAccountId", "fortniteToken");
240
+ console.log(entry.rank, entry.pointsEarned, entry.trackedStats);
241
+ ```
242
+
243
+ > **Note:** PR is a rolling aggregate of a player's best 20 events (`countingEvents` caps at 20). Epic does not publish how much any individual tournament contributed, so there is no per-event PR figure in this data.
244
+
245
+ ---
246
+
154
247
  ### Quests - **NEW**
155
248
 
156
249
  Access player quest progress, XP, and account level information.
package/dist/client.d.ts CHANGED
@@ -20,6 +20,7 @@ import { CrewResource } from "./resources/crew";
20
20
  import { MapResource } from "./resources/map";
21
21
  import { PlaylistsResource } from "./resources/playlists";
22
22
  import { SpritesResource } from "./resources/sprites";
23
+ import { PowerRankingsResource } from "./resources/powerrankings";
23
24
  export interface ClientOptions {
24
25
  apiKey: string;
25
26
  baseUrl?: string;
@@ -49,6 +50,7 @@ export declare class FortniteAPI {
49
50
  map: MapResource;
50
51
  playlists: PlaylistsResource;
51
52
  sprites: SpritesResource;
53
+ powerRankings: PowerRankingsResource;
52
54
  constructor(options: ClientOptions);
53
55
  /**
54
56
  * Internal method to make HTTP requests
package/dist/client.js CHANGED
@@ -24,6 +24,7 @@ const crew_1 = require("./resources/crew");
24
24
  const map_1 = require("./resources/map");
25
25
  const playlists_1 = require("./resources/playlists");
26
26
  const sprites_1 = require("./resources/sprites");
27
+ const powerrankings_1 = require("./resources/powerrankings");
27
28
  class FortniteAPI {
28
29
  constructor(options) {
29
30
  this.apiKey = options.apiKey;
@@ -52,6 +53,7 @@ class FortniteAPI {
52
53
  this.map = new map_1.MapResource(this);
53
54
  this.playlists = new playlists_1.PlaylistsResource(this);
54
55
  this.sprites = new sprites_1.SpritesResource(this);
56
+ this.powerRankings = new powerrankings_1.PowerRankingsResource(this);
55
57
  }
56
58
  /**
57
59
  * Internal method to make HTTP requests
@@ -41,10 +41,32 @@ export declare class EventsResource {
41
41
  getPlayerWindowStanding(eventId: string, eventWindowId: string, accountId: string): Promise<PlayerWindowStanding>;
42
42
  /**
43
43
  * Get a player's event participation history.
44
- * Uses the V2 events endpoint with service token — no user token required.
44
+ *
45
+ * **`fortniteToken` is mandatory.** Epic serves this history only to the player
46
+ * it belongs to — service auth is rejected, so a token-less call returns **401**.
47
+ * Get a token through the OAuth flow: `client.oauth.getToken()` then
48
+ * `client.oauth.complete()`.
49
+ *
50
+ * Returns one score object per event window: `scoreKey` (gameId, eventId,
51
+ * eventWindowId), `teamId`, `teamAccountIds` (so team size is
52
+ * `teamAccountIds.length`), `pointsEarned`, `score`, `rank` (the placement),
53
+ * `percentile`, `pointBreakdown`, `sessionHistory` (one entry per match, with
54
+ * `endTime` and tracked stats) and `unscoredSessions`.
55
+ *
56
+ * Note that Epic returns raw event/window IDs here, not display names — pair it
57
+ * with `client.tournaments.getTracker()` for human-readable event names and the
58
+ * official window begin/end times.
59
+ *
60
+ * If you do not have the player's token, look a single tournament up instead with
61
+ * `client.tournaments.getPlayerWindowMatches()`, which needs no user token.
62
+ *
45
63
  * @param accountId - Epic account ID of the player
64
+ * @param fortniteToken - Required. Fortnite access token of that same player.
65
+ *
66
+ * @throws {FortniteAPIError} 401 when the token is missing, expired, or belongs to
67
+ * a different account
46
68
  */
47
- getPlayerEventHistory(accountId: string): Promise<any>;
69
+ getPlayerEventHistory(accountId: string, fortniteToken: string): Promise<any>;
48
70
  /**
49
71
  * Get the raw token set for one or more players.
50
72
  * Tokens are eligibility flags earned by participating in tournaments
@@ -56,11 +56,33 @@ class EventsResource {
56
56
  }
57
57
  /**
58
58
  * Get a player's event participation history.
59
- * Uses the V2 events endpoint with service token — no user token required.
59
+ *
60
+ * **`fortniteToken` is mandatory.** Epic serves this history only to the player
61
+ * it belongs to — service auth is rejected, so a token-less call returns **401**.
62
+ * Get a token through the OAuth flow: `client.oauth.getToken()` then
63
+ * `client.oauth.complete()`.
64
+ *
65
+ * Returns one score object per event window: `scoreKey` (gameId, eventId,
66
+ * eventWindowId), `teamId`, `teamAccountIds` (so team size is
67
+ * `teamAccountIds.length`), `pointsEarned`, `score`, `rank` (the placement),
68
+ * `percentile`, `pointBreakdown`, `sessionHistory` (one entry per match, with
69
+ * `endTime` and tracked stats) and `unscoredSessions`.
70
+ *
71
+ * Note that Epic returns raw event/window IDs here, not display names — pair it
72
+ * with `client.tournaments.getTracker()` for human-readable event names and the
73
+ * official window begin/end times.
74
+ *
75
+ * If you do not have the player's token, look a single tournament up instead with
76
+ * `client.tournaments.getPlayerWindowMatches()`, which needs no user token.
77
+ *
60
78
  * @param accountId - Epic account ID of the player
79
+ * @param fortniteToken - Required. Fortnite access token of that same player.
80
+ *
81
+ * @throws {FortniteAPIError} 401 when the token is missing, expired, or belongs to
82
+ * a different account
61
83
  */
62
- async getPlayerEventHistory(accountId) {
63
- return this.client.request(`/events/players/${encodeURIComponent(accountId)}/history`, {}, "v2");
84
+ async getPlayerEventHistory(accountId, fortniteToken) {
85
+ return this.client.request(`/events/players/${encodeURIComponent(accountId)}/history`, { headers: { "x-fortnite-token": fortniteToken } }, "v2");
64
86
  }
65
87
  /**
66
88
  * Get the raw token set for one or more players.
@@ -0,0 +1,95 @@
1
+ import { FortniteAPI } from "../client";
2
+ import { PowerRankingsLeaderboard, PowerRankingsSearchResponse, PowerRankingsArchiveEntry, PowerRankingsPlayerEntry } from "../types";
3
+ /**
4
+ * Power Rankings Resource
5
+ *
6
+ * Epic's own competitive Power Rankings ladder — the same figure shown in the
7
+ * in-game Compete tab and on Fortnite's competitive site. It is read live from
8
+ * Epic's events service (`epicgames_dreamyparadox`); nothing here is computed by
9
+ * the API or sourced from a third-party tracker.
10
+ *
11
+ * The ladder covers the top 10,000 players (100 pages x 100 entries) and is
12
+ * chapter-scoped (e.g. `"C7 Power Rankings"`).
13
+ *
14
+ * Epic publishes the ladder as a periodic snapshot: every entry on every page
15
+ * carries the same `sessionHistory[0].endTime`, which is the date of the snapshot
16
+ * currently being served. The API re-fetches Epic hourly and rebuilds the search
17
+ * index every 2 hours, so polling more often than that will not surface newer data.
18
+ *
19
+ * All methods require the `pro` or `custom` plan.
20
+ */
21
+ export declare class PowerRankingsResource {
22
+ private client;
23
+ constructor(client: FortniteAPI);
24
+ /**
25
+ * Get a page of the Power Rankings leaderboard.
26
+ *
27
+ * 100 entries per page, 100 pages total (top 10,000). No `x-fortnite-token`
28
+ * needed for the global page.
29
+ *
30
+ * Per entry: `rank`, `pointsEarned` / `score` (the PR value),
31
+ * `teamAccountIds`, `teamAccountDisplayNames`, `playerFlagTokens` (region), and
32
+ * `sessionHistory[0].trackedStats` with `PR`, `countingEvents` (capped at 20),
33
+ * `peakPerf`, `deltaPR`, `peakPR` and `deltaPosition`.
34
+ *
35
+ * @param options.page - Zero-indexed page (default: 0, max: 99)
36
+ * @param options.accountId - Epic account ID of the token holder. Required when
37
+ * `fortniteToken` is supplied, ignored otherwise.
38
+ * @param fortniteToken - Optional. When supplied together with `accountId`, the
39
+ * response also carries that player's own entry as
40
+ * `playerEntry` (`null` when they are unranked), even if
41
+ * they sit outside the requested page.
42
+ */
43
+ getLeaderboard(options?: {
44
+ page?: number;
45
+ accountId?: string;
46
+ }, fortniteToken?: string): Promise<PowerRankingsLeaderboard>;
47
+ /**
48
+ * Search Power Rankings players by display name (partial, case-insensitive).
49
+ *
50
+ * Backed by an in-memory index built from the full 10,000-player leaderboard and
51
+ * rebuilt every 2 hours. **No `x-fortnite-token` required** — this is the simplest
52
+ * way to resolve a player's PR when you do not have their OAuth token.
53
+ *
54
+ * @param q - Display name search term (partial match; 2+ characters recommended)
55
+ * @param limit - Max results (default: 10, max: 50)
56
+ */
57
+ search(q: string, limit?: number): Promise<PowerRankingsSearchResponse>;
58
+ /**
59
+ * Look up a player's live Power Rankings entry by display name or account ID.
60
+ *
61
+ * **`fortniteToken` is mandatory, and it must belong to the player being looked
62
+ * up.** Epic rejects the `teamAccountIds` filter this endpoint relies on when the
63
+ * request carries service auth, so a token-less call returns **400** for every
64
+ * account — including accounts that sit inside the top 10,000. With the token the
65
+ * entry resolves even when the player is ranked beyond the top 10,000.
66
+ *
67
+ * Get a token through the OAuth flow: `client.oauth.getToken()` then
68
+ * `client.oauth.complete()`.
69
+ *
70
+ * If you do not have the player's token, use {@link search} or
71
+ * {@link getFromArchive} instead — same PR figures, no OAuth required.
72
+ *
73
+ * @param identifier - Epic display name or 32-char hex account ID (clan tags are
74
+ * stripped automatically)
75
+ * @param fortniteToken - Required. Fortnite access token of the player being looked up.
76
+ *
77
+ * @throws {FortniteAPIError} 400 when the token is missing, expired, or belongs to
78
+ * a different account
79
+ * @throws {FortniteAPIError} 404 when the player has no Power Rankings entry
80
+ */
81
+ getPlayer(identifier: string, fortniteToken: string): Promise<PowerRankingsPlayerEntry>;
82
+ /**
83
+ * Look up a player's most recent archived Power Rankings entry by account ID.
84
+ *
85
+ * **No `x-fortnite-token` required.** Works for any account that has appeared in
86
+ * the top-10,000 leaderboard. Returns `rank`, `score`, `bestRank`, `peakPr`,
87
+ * `deltaPr`, `countingEvents`, `seasonLabel` and `lastUpdated` — read the
88
+ * `lastUpdated` timestamp to see how fresh the archived row is.
89
+ *
90
+ * @param accountId - 32-char hex Epic account ID
91
+ *
92
+ * @throws {FortniteAPIError} 404 when the account is not in the archive
93
+ */
94
+ getFromArchive(accountId: string): Promise<PowerRankingsArchiveEntry>;
95
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PowerRankingsResource = void 0;
4
+ /**
5
+ * Power Rankings Resource
6
+ *
7
+ * Epic's own competitive Power Rankings ladder — the same figure shown in the
8
+ * in-game Compete tab and on Fortnite's competitive site. It is read live from
9
+ * Epic's events service (`epicgames_dreamyparadox`); nothing here is computed by
10
+ * the API or sourced from a third-party tracker.
11
+ *
12
+ * The ladder covers the top 10,000 players (100 pages x 100 entries) and is
13
+ * chapter-scoped (e.g. `"C7 Power Rankings"`).
14
+ *
15
+ * Epic publishes the ladder as a periodic snapshot: every entry on every page
16
+ * carries the same `sessionHistory[0].endTime`, which is the date of the snapshot
17
+ * currently being served. The API re-fetches Epic hourly and rebuilds the search
18
+ * index every 2 hours, so polling more often than that will not surface newer data.
19
+ *
20
+ * All methods require the `pro` or `custom` plan.
21
+ */
22
+ class PowerRankingsResource {
23
+ constructor(client) {
24
+ this.client = client;
25
+ }
26
+ /**
27
+ * Get a page of the Power Rankings leaderboard.
28
+ *
29
+ * 100 entries per page, 100 pages total (top 10,000). No `x-fortnite-token`
30
+ * needed for the global page.
31
+ *
32
+ * Per entry: `rank`, `pointsEarned` / `score` (the PR value),
33
+ * `teamAccountIds`, `teamAccountDisplayNames`, `playerFlagTokens` (region), and
34
+ * `sessionHistory[0].trackedStats` with `PR`, `countingEvents` (capped at 20),
35
+ * `peakPerf`, `deltaPR`, `peakPR` and `deltaPosition`.
36
+ *
37
+ * @param options.page - Zero-indexed page (default: 0, max: 99)
38
+ * @param options.accountId - Epic account ID of the token holder. Required when
39
+ * `fortniteToken` is supplied, ignored otherwise.
40
+ * @param fortniteToken - Optional. When supplied together with `accountId`, the
41
+ * response also carries that player's own entry as
42
+ * `playerEntry` (`null` when they are unranked), even if
43
+ * they sit outside the requested page.
44
+ */
45
+ async getLeaderboard(options, fortniteToken) {
46
+ const params = new URLSearchParams();
47
+ if (options?.page != null)
48
+ params.append("page", String(options.page));
49
+ if (options?.accountId)
50
+ params.append("accountId", options.accountId);
51
+ const qs = params.toString();
52
+ const requestOptions = fortniteToken
53
+ ? { headers: { "x-fortnite-token": fortniteToken } }
54
+ : undefined;
55
+ return this.client.request(`/events/powerrankings${qs ? `?${qs}` : ""}`, requestOptions);
56
+ }
57
+ /**
58
+ * Search Power Rankings players by display name (partial, case-insensitive).
59
+ *
60
+ * Backed by an in-memory index built from the full 10,000-player leaderboard and
61
+ * rebuilt every 2 hours. **No `x-fortnite-token` required** — this is the simplest
62
+ * way to resolve a player's PR when you do not have their OAuth token.
63
+ *
64
+ * @param q - Display name search term (partial match; 2+ characters recommended)
65
+ * @param limit - Max results (default: 10, max: 50)
66
+ */
67
+ async search(q, limit) {
68
+ const params = new URLSearchParams({ q });
69
+ if (limit != null)
70
+ params.append("limit", String(limit));
71
+ return this.client.request(`/events/powerrankings/search?${params.toString()}`);
72
+ }
73
+ /**
74
+ * Look up a player's live Power Rankings entry by display name or account ID.
75
+ *
76
+ * **`fortniteToken` is mandatory, and it must belong to the player being looked
77
+ * up.** Epic rejects the `teamAccountIds` filter this endpoint relies on when the
78
+ * request carries service auth, so a token-less call returns **400** for every
79
+ * account — including accounts that sit inside the top 10,000. With the token the
80
+ * entry resolves even when the player is ranked beyond the top 10,000.
81
+ *
82
+ * Get a token through the OAuth flow: `client.oauth.getToken()` then
83
+ * `client.oauth.complete()`.
84
+ *
85
+ * If you do not have the player's token, use {@link search} or
86
+ * {@link getFromArchive} instead — same PR figures, no OAuth required.
87
+ *
88
+ * @param identifier - Epic display name or 32-char hex account ID (clan tags are
89
+ * stripped automatically)
90
+ * @param fortniteToken - Required. Fortnite access token of the player being looked up.
91
+ *
92
+ * @throws {FortniteAPIError} 400 when the token is missing, expired, or belongs to
93
+ * a different account
94
+ * @throws {FortniteAPIError} 404 when the player has no Power Rankings entry
95
+ */
96
+ async getPlayer(identifier, fortniteToken) {
97
+ return this.client.request(`/events/powerrankings/player/${encodeURIComponent(identifier)}`, { headers: { "x-fortnite-token": fortniteToken } });
98
+ }
99
+ /**
100
+ * Look up a player's most recent archived Power Rankings entry by account ID.
101
+ *
102
+ * **No `x-fortnite-token` required.** Works for any account that has appeared in
103
+ * the top-10,000 leaderboard. Returns `rank`, `score`, `bestRank`, `peakPr`,
104
+ * `deltaPr`, `countingEvents`, `seasonLabel` and `lastUpdated` — read the
105
+ * `lastUpdated` timestamp to see how fresh the archived row is.
106
+ *
107
+ * @param accountId - 32-char hex Epic account ID
108
+ *
109
+ * @throws {FortniteAPIError} 404 when the account is not in the archive
110
+ */
111
+ async getFromArchive(accountId) {
112
+ return this.client.request(`/events/powerrankings/archive/${encodeURIComponent(accountId)}`);
113
+ }
114
+ }
115
+ exports.PowerRankingsResource = PowerRankingsResource;
@@ -1,5 +1,5 @@
1
1
  import { FortniteAPI } from "../client";
2
- import { Leaderboard, TournamentTrackerResponse, TournamentEligibilityResponse, EventTokenEligibilityResponse, CashPrizesResponse, PayoutTable } from "../types";
2
+ import { Leaderboard, TournamentTrackerResponse, TournamentEligibilityResponse, EventTokenEligibilityResponse, CashPrizesResponse, PayoutTable, PlayerSession } from "../types";
3
3
  export declare class TournamentsResource {
4
4
  private client;
5
5
  constructor(client: FortniteAPI);
@@ -61,6 +61,59 @@ export declare class TournamentsResource {
61
61
  leaderboardDef?: string;
62
62
  accountId?: string;
63
63
  }, fortniteToken?: string): Promise<Leaderboard>;
64
+ /**
65
+ * Get a player's result in one tournament window — **no user token required.**
66
+ *
67
+ * Returns their final `rank` (placement), `pointsEarned`, `teamAccountIds` (team
68
+ * size is `teamAccountIds.length`) and every match they played in that window,
69
+ * each with `sessionId`, `endTime` and `trackedStats` (`PLACEMENT_STAT_INDEX`,
70
+ * `TEAM_ELIMS_STAT_INDEX`, `TIME_ALIVE_STAT`, `VICTORY_ROYALE_STAT`, ...).
71
+ *
72
+ * The lookup works by scanning leaderboard pages until the player's team is found.
73
+ * Pass `rankHint` (their approximate final rank) to turn it into a single page
74
+ * fetch — without it up to `maxPages` pages are scanned in order, which is slower
75
+ * and may miss players placed beyond that point.
76
+ *
77
+ * Use this when you do not have the player's OAuth token. For their full history
78
+ * across every tournament, use `client.events.getPlayerEventHistory()` (token
79
+ * required).
80
+ *
81
+ * @param eventId - Event identifier (e.g. `"epicgames_S41_CashCup_DuosZB_OCE"`)
82
+ * @param eventWindowId - Event window identifier (e.g. `"S41_CashCup_DuosZB_Event1Round1_OCE"`)
83
+ * @param accountId - Epic account ID of any player on the team
84
+ * @param options.rankHint - Approximate leaderboard rank, if known — makes this a single page fetch
85
+ * @param options.maxPages - Max leaderboard pages to scan (default: 15, max: 100)
86
+ *
87
+ * @throws {FortniteAPIError} 404 when the player was not found within the scanned pages
88
+ */
89
+ getPlayerWindowMatches(eventId: string, eventWindowId: string, accountId: string, options?: {
90
+ rankHint?: number;
91
+ maxPages?: number;
92
+ }): Promise<any>;
93
+ /**
94
+ * A player's RECENT tournament sessions, grouped by event window. Epic keeps roughly
95
+ * the last 36 hours of this data — it is not a full history. Tournament sessions
96
+ * only: private custom-key matches never appear here.
97
+ *
98
+ * Sourced from Epic's player-scoped download data, which Epic only serves to the
99
+ * player it belongs to — so `fortniteToken` is required (without it Epic returns
100
+ * **403**). For a 180-day participation history use {@link getTracker}; for a
101
+ * token-free lookup scoped to one tournament use {@link getPlayerWindowMatches};
102
+ * for the match a player is in right now use {@link getPlayerSession}.
103
+ *
104
+ * @param accountId - Epic Games Account ID
105
+ * @param fortniteToken - Fortnite access token of that same player (from OAuth flow)
106
+ * @param options.after - Only matches ending at or after this UTC timestamp
107
+ * @param options.before - Only matches ending before this UTC timestamp
108
+ * @param options.region - Region for the events catalogue (default: EU). The sessions themselves are global.
109
+ * @param options.platform - Platform (default: Windows)
110
+ */
111
+ getPlayerMatches(accountId: string, fortniteToken: string, options?: {
112
+ after?: string;
113
+ before?: string;
114
+ region?: string;
115
+ platform?: string;
116
+ }): Promise<any>;
64
117
  /**
65
118
  * Get tournament participation history for a player
66
119
  * Requires user's own Fortnite token
@@ -216,4 +269,26 @@ export declare class TournamentsResource {
216
269
  eventWindowId: string;
217
270
  leaderboardDef?: string;
218
271
  }, teams: string[][], fortniteToken?: string): Promise<Leaderboard>;
272
+ /**
273
+ * The match a consenting player is in right now — any mode: Battle Royale, Reload,
274
+ * Ranked, or a custom-key scrim hosted by anyone. This is the only route to a player's
275
+ * non-tournament matches: Epic exposes no match-history listing. **Custom plan.**
276
+ *
277
+ * Requires that player's OWN Fortnite token: it is verified against `accountId` before
278
+ * anything is forwarded (any other account's token returns **403**). Fortnite kills every
279
+ * other session of an account when the game launches, so a token obtained before the
280
+ * player started playing is dead by the time they play — obtain it from stored device
281
+ * auth (`/oauth/link` once, then `/oauth/refresh-device` on 401), not a one-off login.
282
+ *
283
+ * While the player is in a game, `sessionId` is the replay match ID: pass it to the
284
+ * replay endpoints once the match has ended. `playlist` lets you filter (e.g. scrims)
285
+ * before parsing. Cached 10 s per account (polling faster gains nothing); Epic's own
286
+ * party state lags the real match by about 1-2 minutes; a session ID does not change
287
+ * during a match. Never returns the custom match key (`hasCustomKey` only) nor
288
+ * teammates' state (account ids only). `inParty` is false when the client is offline.
289
+ *
290
+ * @param accountId - Epic Games Account ID
291
+ * @param fortniteToken - That same player's Fortnite access token
292
+ */
293
+ getPlayerSession(accountId: string, fortniteToken: string): Promise<PlayerSession>;
219
294
  }
@@ -92,6 +92,71 @@ class TournamentsResource {
92
92
  : undefined;
93
93
  return this.client.request(`/events/global/leaderboard?${query.toString()}`, options);
94
94
  }
95
+ /**
96
+ * Get a player's result in one tournament window — **no user token required.**
97
+ *
98
+ * Returns their final `rank` (placement), `pointsEarned`, `teamAccountIds` (team
99
+ * size is `teamAccountIds.length`) and every match they played in that window,
100
+ * each with `sessionId`, `endTime` and `trackedStats` (`PLACEMENT_STAT_INDEX`,
101
+ * `TEAM_ELIMS_STAT_INDEX`, `TIME_ALIVE_STAT`, `VICTORY_ROYALE_STAT`, ...).
102
+ *
103
+ * The lookup works by scanning leaderboard pages until the player's team is found.
104
+ * Pass `rankHint` (their approximate final rank) to turn it into a single page
105
+ * fetch — without it up to `maxPages` pages are scanned in order, which is slower
106
+ * and may miss players placed beyond that point.
107
+ *
108
+ * Use this when you do not have the player's OAuth token. For their full history
109
+ * across every tournament, use `client.events.getPlayerEventHistory()` (token
110
+ * required).
111
+ *
112
+ * @param eventId - Event identifier (e.g. `"epicgames_S41_CashCup_DuosZB_OCE"`)
113
+ * @param eventWindowId - Event window identifier (e.g. `"S41_CashCup_DuosZB_Event1Round1_OCE"`)
114
+ * @param accountId - Epic account ID of any player on the team
115
+ * @param options.rankHint - Approximate leaderboard rank, if known — makes this a single page fetch
116
+ * @param options.maxPages - Max leaderboard pages to scan (default: 15, max: 100)
117
+ *
118
+ * @throws {FortniteAPIError} 404 when the player was not found within the scanned pages
119
+ */
120
+ async getPlayerWindowMatches(eventId, eventWindowId, accountId, options) {
121
+ const params = new URLSearchParams();
122
+ if (options?.rankHint != null)
123
+ params.append("rankHint", String(options.rankHint));
124
+ if (options?.maxPages != null)
125
+ params.append("maxPages", String(options.maxPages));
126
+ const qs = params.toString();
127
+ return this.client.request(`/events/${encodeURIComponent(eventId)}/${encodeURIComponent(eventWindowId)}/player/${encodeURIComponent(accountId)}/matches${qs ? `?${qs}` : ""}`);
128
+ }
129
+ /**
130
+ * A player's RECENT tournament sessions, grouped by event window. Epic keeps roughly
131
+ * the last 36 hours of this data — it is not a full history. Tournament sessions
132
+ * only: private custom-key matches never appear here.
133
+ *
134
+ * Sourced from Epic's player-scoped download data, which Epic only serves to the
135
+ * player it belongs to — so `fortniteToken` is required (without it Epic returns
136
+ * **403**). For a 180-day participation history use {@link getTracker}; for a
137
+ * token-free lookup scoped to one tournament use {@link getPlayerWindowMatches};
138
+ * for the match a player is in right now use {@link getPlayerSession}.
139
+ *
140
+ * @param accountId - Epic Games Account ID
141
+ * @param fortniteToken - Fortnite access token of that same player (from OAuth flow)
142
+ * @param options.after - Only matches ending at or after this UTC timestamp
143
+ * @param options.before - Only matches ending before this UTC timestamp
144
+ * @param options.region - Region for the events catalogue (default: EU). The sessions themselves are global.
145
+ * @param options.platform - Platform (default: Windows)
146
+ */
147
+ async getPlayerMatches(accountId, fortniteToken, options) {
148
+ const params = new URLSearchParams();
149
+ if (options?.after)
150
+ params.append("after", options.after);
151
+ if (options?.before)
152
+ params.append("before", options.before);
153
+ if (options?.region)
154
+ params.append("region", options.region);
155
+ if (options?.platform)
156
+ params.append("platform", options.platform);
157
+ const qs = params.toString();
158
+ return this.client.request(`/events/player/${encodeURIComponent(accountId)}/matches${qs ? `?${qs}` : ""}`, { headers: { "x-fortnite-token": fortniteToken } });
159
+ }
95
160
  /**
96
161
  * Get tournament participation history for a player
97
162
  * Requires user's own Fortnite token
@@ -297,5 +362,29 @@ class TournamentsResource {
297
362
  }
298
363
  return this.client.request(`/events/leaderboard?${query.toString()}`, options, "v2");
299
364
  }
365
+ /**
366
+ * The match a consenting player is in right now — any mode: Battle Royale, Reload,
367
+ * Ranked, or a custom-key scrim hosted by anyone. This is the only route to a player's
368
+ * non-tournament matches: Epic exposes no match-history listing. **Custom plan.**
369
+ *
370
+ * Requires that player's OWN Fortnite token: it is verified against `accountId` before
371
+ * anything is forwarded (any other account's token returns **403**). Fortnite kills every
372
+ * other session of an account when the game launches, so a token obtained before the
373
+ * player started playing is dead by the time they play — obtain it from stored device
374
+ * auth (`/oauth/link` once, then `/oauth/refresh-device` on 401), not a one-off login.
375
+ *
376
+ * While the player is in a game, `sessionId` is the replay match ID: pass it to the
377
+ * replay endpoints once the match has ended. `playlist` lets you filter (e.g. scrims)
378
+ * before parsing. Cached 10 s per account (polling faster gains nothing); Epic's own
379
+ * party state lags the real match by about 1-2 minutes; a session ID does not change
380
+ * during a match. Never returns the custom match key (`hasCustomKey` only) nor
381
+ * teammates' state (account ids only). `inParty` is false when the client is offline.
382
+ *
383
+ * @param accountId - Epic Games Account ID
384
+ * @param fortniteToken - That same player's Fortnite access token
385
+ */
386
+ async getPlayerSession(accountId, fortniteToken) {
387
+ return this.client.request(`/events/player/${encodeURIComponent(accountId)}/session`, { headers: { "x-fortnite-token": fortniteToken } });
388
+ }
300
389
  }
301
390
  exports.TournamentsResource = TournamentsResource;
@@ -733,6 +733,110 @@ export interface PlayerWindowStanding {
733
733
  percentile?: number;
734
734
  sessionHistory: PlayerWindowStandingSession[];
735
735
  }
736
+ /**
737
+ * Tracked stats carried on a Power Rankings ladder entry.
738
+ * `PR` is the Power Rankings score itself; `countingEvents` is capped at 20
739
+ * (Epic only counts a player's best 20 events).
740
+ */
741
+ export interface PowerRankingsTrackedStats {
742
+ PR: number;
743
+ countingEvents: number;
744
+ peakPerf: number;
745
+ deltaPR: number;
746
+ peakPR: number;
747
+ deltaPosition?: number;
748
+ }
749
+ export interface PowerRankingsSession {
750
+ sessionId: string;
751
+ /** Date of the Epic snapshot this ladder was published from — identical across every entry. */
752
+ endTime: string;
753
+ trackedStats: PowerRankingsTrackedStats;
754
+ }
755
+ export interface PowerRankingsLeaderboardEntry {
756
+ gameId: string;
757
+ eventId: string;
758
+ eventWindowId: string;
759
+ teamId: string;
760
+ teamAccountIds: string[];
761
+ teamAccountDisplayNames?: string[];
762
+ /** The player's PR value. `score` carries the same number. */
763
+ pointsEarned: number;
764
+ score: number;
765
+ rank: number;
766
+ percentile: number;
767
+ pointBreakdown: Record<string, {
768
+ timesAchieved: number;
769
+ pointsEarned: number;
770
+ }>;
771
+ sessionHistory: PowerRankingsSession[];
772
+ /** Region/geo identity flag, e.g. `GroupIdentity_GeoIdentity_denmark`. */
773
+ playerFlagTokens?: Record<string, string>;
774
+ unscoredSessions?: any[];
775
+ }
776
+ /**
777
+ * Returned by GET /api/v1/events/powerrankings
778
+ */
779
+ export interface PowerRankingsLeaderboard {
780
+ gameId: string;
781
+ eventId: string;
782
+ eventWindowId: string;
783
+ page: number;
784
+ totalPages: number;
785
+ updatedTime: string;
786
+ entries: PowerRankingsLeaderboardEntry[];
787
+ /**
788
+ * The token holder's own entry — present only when both `x-fortnite-token` and
789
+ * `accountId` were supplied. `null` when that player is unranked.
790
+ */
791
+ playerEntry?: PowerRankingsLeaderboardEntry | null;
792
+ }
793
+ export interface PowerRankingsSearchResult {
794
+ accountId: string;
795
+ displayName: string;
796
+ rank: number;
797
+ score: number;
798
+ countingEvents: number;
799
+ peakPr: number;
800
+ deltaPr: number;
801
+ }
802
+ /**
803
+ * Returned by GET /api/v1/events/powerrankings/search
804
+ */
805
+ export interface PowerRankingsSearchResponse {
806
+ query: string;
807
+ total: number;
808
+ results: PowerRankingsSearchResult[];
809
+ }
810
+ /**
811
+ * Returned by GET /api/v1/events/powerrankings/player/{identifier}
812
+ * (requires the x-fortnite-token of the player being looked up)
813
+ */
814
+ export interface PowerRankingsPlayerEntry {
815
+ accountId: string;
816
+ displayName: string;
817
+ eventId: string;
818
+ eventWindowId: string;
819
+ rank?: number;
820
+ pointsEarned?: number;
821
+ trackedStats?: PowerRankingsTrackedStats;
822
+ }
823
+ /**
824
+ * Returned by GET /api/v1/events/powerrankings/archive/{accountId}
825
+ */
826
+ export interface PowerRankingsArchiveEntry {
827
+ accountId: string;
828
+ displayName: string;
829
+ rank: number;
830
+ score: number;
831
+ bestRank: number;
832
+ peakPr: number;
833
+ deltaPr: number;
834
+ countingEvents: number;
835
+ /** When this archived row was last refreshed — not the date of Epic's snapshot. */
836
+ lastUpdated: string;
837
+ /** Chapter the ladder belongs to, e.g. `"C7 Power Rankings"`. */
838
+ seasonLabel: string;
839
+ }
736
840
  export interface PayoutTableReward {
737
841
  itemType: string;
738
842
  itemId?: string;
@@ -1083,3 +1187,30 @@ export interface SpriteBoonsResponse {
1083
1187
  status: number;
1084
1188
  data: SpriteBoon[];
1085
1189
  }
1190
+ /** GET /events/player/{accountId}/session — the match a consenting player is in right now. */
1191
+ export interface PlayerSession {
1192
+ accountId: string;
1193
+ /** False when the player's client is offline; no other field is meaningful then. */
1194
+ inParty: boolean;
1195
+ inMatch: boolean;
1196
+ /** The replay match ID while in a game; null in the lobby or offline. */
1197
+ sessionId: string | null;
1198
+ partySize?: number;
1199
+ isLeader?: boolean;
1200
+ /** e.g. "PreLobby" | "InGame" */
1201
+ location?: string | null;
1202
+ gameMode?: string | null;
1203
+ /** e.g. "playlist_showdown_cts_solo" — what they play, or what they have selected in the lobby. */
1204
+ playlist?: string | null;
1205
+ region?: string | null;
1206
+ /** The party runs on a custom match key. The key itself is never returned. */
1207
+ hasCustomKey?: boolean;
1208
+ matchStartedAt?: string | null;
1209
+ playersLeft?: number | null;
1210
+ /** Teammates by account id only. */
1211
+ members?: Array<{
1212
+ accountId: string | null;
1213
+ isLeader: boolean;
1214
+ }>;
1215
+ note?: string;
1216
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaelouuu/fortnite-api",
3
- "version": "8.1.0",
3
+ "version": "9.1.0",
4
4
  "description": "SDK for Fortnite API - api-fortnite.com - Author : Yael Brinkert",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",