@yaelouuu/fortnite-api 9.1.1 → 9.2.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
@@ -47,16 +47,17 @@ const leaderboard = await client.tournaments.getLeaderboard({
47
47
 
48
48
  ### Shop
49
49
 
50
- Access the Fortnite Item Shop and Battle Pass data.
50
+ Access the current Fortnite Item Shop.
51
51
 
52
52
  ```typescript
53
53
  // Get current item shop
54
54
  const shop = await client.shop.getCurrent();
55
-
56
- // Get current Battle Pass
57
- const battlePass = await client.battlepass.getBattlePass();
58
55
  ```
59
56
 
57
+ > `client.battlepass.getBattlePass()` is deprecated: the endpoint behind it
58
+ > (`/api/v1/shop/battlepass`) never returned the Battle Pass, only Epic's legacy 2021 news block.
59
+ > For the Battle Pass call `GET /api/v2/battlepass`.
60
+
60
61
  ---
61
62
 
62
63
  ### Tournaments
@@ -158,7 +159,7 @@ if (session.inMatch && session.playlist === "playlist_showdown_cts_solo") {
158
159
  }
159
160
  ```
160
161
 
161
- Read before building on it: the token flow authenticates as the Fortnite client, not as your application — Epic warns the player accordingly, and if you ship an Epic Account Services application its developer terms do not allow routing your users through it (suited to tools a player runs for themselves, not third-party apps asking other players to log in); 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
+ Read before building on it: the token flow authenticates as the Fortnite client, not as your application — Epic warns the player accordingly, and if you ship an Epic Account Services application its developer terms do not allow routing your users through it (suited to tools a player runs for themselves, not third-party apps asking other players to log in); 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 store the `deviceAuth` that `/oauth/complete` returns and re-authenticate with `/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
163
 
163
164
  #### Check Tournament Eligibility
164
165
  Verify if a player meets requirements for major tournaments (e.g., 14 tournaments in 180 days):
@@ -438,26 +439,34 @@ const psnAuth = await client.account.getExternalAuth('accountId123', 'psn');
438
439
 
439
440
  ---
440
441
 
441
- ### News - **NEW**
442
+ ### News
442
443
 
443
- Get Fortnite news and announcements for all game modes.
444
+ The in-game lobby news carousel (Epic's "message of the day"), fetched live from Epic as a
445
+ generic account and cached 10 minutes, plus the emergency notices. Pro and Custom plans.
444
446
 
445
447
  ```typescript
446
- // Get Battle Royale news
447
- const brNews = await client.news.getBRNews();
448
- // Returns: MOTDs, platform messages, images, and videos
448
+ // Battle Royale lobby news — optional language and platform (default en / Windows)
449
+ const br = await client.news.getBRNews();
450
+ const brFr = await client.news.getBRNews("fr", "PS5");
451
+ // br.motds[0] → { id, position, title, body, tileTitle, image, tileImage,
452
+ // images, tileImages, buttons: [{ text, action, offerId, linkId }], contentHash }
453
+
454
+ // Fortnite Festival has its own rotation
455
+ const festival = await client.news.getFestivalNews();
449
456
 
450
- // Get Save The World news
451
- const stwNews = await client.news.getSTWNews();
457
+ // Save the World / Creative: Epic currently serves its general lobby rotation for both
458
+ const stw = await client.news.getSTWNews();
459
+ const creative = await client.news.getCreativeNews();
452
460
 
453
- // Get Creative news
454
- const creativeNews = await client.news.getCreativeNews();
461
+ // Emergency notices (warning banners), e.g. a mode leaving
462
+ const notices = await client.news.getNotices();
455
463
 
456
- // Get all news at once
457
- const allNews = await client.news.getAllNews();
458
- // Returns: { br, stw, creative, lastModified }
464
+ // Everything at once: { br, stw, creative, festival, notices }
465
+ const all = await client.news.getAllNews("en", "Android");
459
466
  ```
460
467
 
468
+ Epic personalises the carousel per player, so a real account may see a slightly different set.
469
+
461
470
  ---
462
471
 
463
472
  ### Cosmetics - **NEW**
@@ -736,6 +745,14 @@ MIT
736
745
 
737
746
  ## 🆕 Changelog
738
747
 
748
+ ### v9.2.0 (2026-09-27)
749
+ - 🐛 **News now returns the live lobby news.** `/api/v1/news*` used to return Epic's legacy CMS
750
+ news blocks, which Epic stopped updating in 2020–2023. They now return the carousel the game
751
+ shows today, with a new shape (`NewsFeed`: `motds[]` with title, body, images, shop/island
752
+ buttons). The old `NewsResponse`/`BRNews`/`STWNews`/`CreativeNews` types are deprecated aliases.
753
+ - ✨ `news.getFestivalNews()`, `news.getNotices()`; every news method takes an optional `platform`.
754
+ - ⚠️ `battlepass.getBattlePass()` deprecated — its endpoint never returned the Battle Pass.
755
+
739
756
  ### v4.3.0 (2026-01-08)
740
757
  - ✨ **NEW** `NewsResource` with 4 methods:
741
758
  - Battle Royale news
@@ -4,7 +4,10 @@ export declare class BattlePassResource {
4
4
  private client;
5
5
  constructor(client: FortniteAPI);
6
6
  /**
7
- * Get current Battle Pass content and rewards
7
+ * @deprecated Despite its name, GET /api/v1/shop/battlepass never returned the Battle Pass:
8
+ * it returns Epic's legacy "battleroyalenews" CMS block, which Epic stopped updating in 2021.
9
+ * For current lobby news use `client.news.getBRNews()`; for the Battle Pass call
10
+ * GET /api/v2/battlepass.
8
11
  * @param lang - Language code (default: en)
9
12
  */
10
13
  getBattlePass(lang?: string): Promise<BattlePass>;
@@ -6,7 +6,10 @@ class BattlePassResource {
6
6
  this.client = client;
7
7
  }
8
8
  /**
9
- * Get current Battle Pass content and rewards
9
+ * @deprecated Despite its name, GET /api/v1/shop/battlepass never returned the Battle Pass:
10
+ * it returns Epic's legacy "battleroyalenews" CMS block, which Epic stopped updating in 2021.
11
+ * For current lobby news use `client.news.getBRNews()`; for the Battle Pass call
12
+ * GET /api/v2/battlepass.
10
13
  * @param lang - Language code (default: en)
11
14
  */
12
15
  async getBattlePass(lang) {
@@ -1,26 +1,34 @@
1
1
  import { FortniteAPI } from "../client";
2
- import { NewsResponse, BRNews, STWNews, CreativeNews, AllNews } from "../types";
2
+ import { NewsFeed, NewsNotice, NewsPlatform, AllNews } from "../types";
3
+ /**
4
+ * The in-game lobby news carousel, fetched live from Epic as a generic account (no Battle
5
+ * Pass, US / NA-East) and cached 10 minutes. Epic personalises the carousel per player, so a
6
+ * real account may see a slightly different set. Pro and Custom plans.
7
+ */
3
8
  export declare class NewsResource {
4
9
  private client;
5
10
  constructor(client: FortniteAPI);
11
+ private query;
6
12
  /**
7
- * Get Battle Royale news
13
+ * Battle Royale lobby news
8
14
  * @param lang - Language code (default: en)
15
+ * @param platform - Platform (default: Windows); Epic varies some entries by platform
9
16
  */
10
- getBRNews(lang?: string): Promise<NewsResponse<BRNews>>;
17
+ getBRNews(lang?: string, platform?: NewsPlatform | string): Promise<NewsFeed>;
11
18
  /**
12
- * Get Save The World news
13
- * @param lang - Language code (default: en)
19
+ * Lobby news Epic serves for Save the World. As of September 2026 Epic runs no separate
20
+ * rotation for it: this is Epic's general lobby rotation (same entries as getCreativeNews).
14
21
  */
15
- getSTWNews(lang?: string): Promise<NewsResponse<STWNews>>;
22
+ getSTWNews(lang?: string, platform?: NewsPlatform | string): Promise<NewsFeed>;
16
23
  /**
17
- * Get Creative news
18
- * @param lang - Language code (default: en)
19
- */
20
- getCreativeNews(lang?: string): Promise<NewsResponse<CreativeNews>>;
21
- /**
22
- * Get all news (BR, STW, Creative)
23
- * @param lang - Language code (default: en)
24
+ * Lobby news Epic serves for Creative. As of September 2026 Epic runs no separate rotation
25
+ * for it: this is Epic's general lobby rotation (same entries as getSTWNews).
24
26
  */
25
- getAllNews(lang?: string): Promise<NewsResponse<AllNews>>;
27
+ getCreativeNews(lang?: string, platform?: NewsPlatform | string): Promise<NewsFeed>;
28
+ /** Fortnite Festival lobby news. */
29
+ getFestivalNews(lang?: string, platform?: NewsPlatform | string): Promise<NewsFeed>;
30
+ /** Current emergency notices (in-game warning banners). Empty when Epic has none up. */
31
+ getNotices(lang?: string): Promise<NewsNotice[]>;
32
+ /** Every mode's lobby news plus the emergency notices, in one call. */
33
+ getAllNews(lang?: string, platform?: NewsPlatform | string): Promise<AllNews>;
26
34
  }
@@ -1,41 +1,57 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NewsResource = void 0;
4
+ /**
5
+ * The in-game lobby news carousel, fetched live from Epic as a generic account (no Battle
6
+ * Pass, US / NA-East) and cached 10 minutes. Epic personalises the carousel per player, so a
7
+ * real account may see a slightly different set. Pro and Custom plans.
8
+ */
4
9
  class NewsResource {
5
10
  constructor(client) {
6
11
  this.client = client;
7
12
  }
8
- /**
9
- * Get Battle Royale news
10
- * @param lang - Language code (default: en)
11
- */
12
- async getBRNews(lang) {
13
- const query = lang ? `?lang=${encodeURIComponent(lang)}` : "";
14
- return this.client.request(`/news/br${query}`);
13
+ query(lang, platform) {
14
+ const params = new URLSearchParams();
15
+ if (lang)
16
+ params.set("lang", lang);
17
+ if (platform)
18
+ params.set("platform", platform);
19
+ const q = params.toString();
20
+ return q ? `?${q}` : "";
15
21
  }
16
22
  /**
17
- * Get Save The World news
23
+ * Battle Royale lobby news
18
24
  * @param lang - Language code (default: en)
25
+ * @param platform - Platform (default: Windows); Epic varies some entries by platform
19
26
  */
20
- async getSTWNews(lang) {
21
- const query = lang ? `?lang=${encodeURIComponent(lang)}` : "";
22
- return this.client.request(`/news/stw${query}`);
27
+ async getBRNews(lang, platform) {
28
+ return this.client.request(`/news/br${this.query(lang, platform)}`);
23
29
  }
24
30
  /**
25
- * Get Creative news
26
- * @param lang - Language code (default: en)
31
+ * Lobby news Epic serves for Save the World. As of September 2026 Epic runs no separate
32
+ * rotation for it: this is Epic's general lobby rotation (same entries as getCreativeNews).
27
33
  */
28
- async getCreativeNews(lang) {
29
- const query = lang ? `?lang=${encodeURIComponent(lang)}` : "";
30
- return this.client.request(`/news/creative${query}`);
34
+ async getSTWNews(lang, platform) {
35
+ return this.client.request(`/news/stw${this.query(lang, platform)}`);
31
36
  }
32
37
  /**
33
- * Get all news (BR, STW, Creative)
34
- * @param lang - Language code (default: en)
38
+ * Lobby news Epic serves for Creative. As of September 2026 Epic runs no separate rotation
39
+ * for it: this is Epic's general lobby rotation (same entries as getSTWNews).
35
40
  */
36
- async getAllNews(lang) {
37
- const query = lang ? `?lang=${encodeURIComponent(lang)}` : "";
38
- return this.client.request(`/news${query}`);
41
+ async getCreativeNews(lang, platform) {
42
+ return this.client.request(`/news/creative${this.query(lang, platform)}`);
43
+ }
44
+ /** Fortnite Festival lobby news. */
45
+ async getFestivalNews(lang, platform) {
46
+ return this.client.request(`/news/festival${this.query(lang, platform)}`);
47
+ }
48
+ /** Current emergency notices (in-game warning banners). Empty when Epic has none up. */
49
+ async getNotices(lang) {
50
+ return this.client.request(`/news/notices${this.query(lang)}`);
51
+ }
52
+ /** Every mode's lobby news plus the emergency notices, in one call. */
53
+ async getAllNews(lang, platform) {
54
+ return this.client.request(`/news${this.query(lang, platform)}`);
39
55
  }
40
56
  }
41
57
  exports.NewsResource = NewsResource;
@@ -282,8 +282,8 @@ export declare class TournamentsResource {
282
282
  * Requires that player's OWN Fortnite token: it is verified against `accountId` before
283
283
  * anything is forwarded (any other account's token returns **403**). Fortnite kills every
284
284
  * other session of an account when the game launches, so a token obtained before the
285
- * player started playing is dead by the time they play — obtain it from stored device
286
- * auth (`/oauth/link` once, then `/oauth/refresh-device` on 401), not a one-off login.
285
+ * player started playing is dead by the time they play — store the `deviceAuth` that
286
+ * `/oauth/complete` returns and re-authenticate with `/oauth/refresh-device` on 401.
287
287
  *
288
288
  * While the player is in a game, `sessionId` is the replay match ID: pass it to the
289
289
  * replay endpoints once the match has ended. `playlist` lets you filter (e.g. scrims)
@@ -375,8 +375,8 @@ class TournamentsResource {
375
375
  * Requires that player's OWN Fortnite token: it is verified against `accountId` before
376
376
  * anything is forwarded (any other account's token returns **403**). Fortnite kills every
377
377
  * other session of an account when the game launches, so a token obtained before the
378
- * player started playing is dead by the time they play — obtain it from stored device
379
- * auth (`/oauth/link` once, then `/oauth/refresh-device` on 401), not a one-off login.
378
+ * player started playing is dead by the time they play — store the `deviceAuth` that
379
+ * `/oauth/complete` returns and re-authenticate with `/oauth/refresh-device` on 401.
380
380
  *
381
381
  * While the player is in a game, `sessionId` is the replay match ID: pass it to the
382
382
  * replay endpoints once the match has ended. `playlist` lets you filter (e.g. scrims)
@@ -887,38 +887,77 @@ export interface EventRewards {
887
887
  currency?: string;
888
888
  }>;
889
889
  }
890
- export interface NewsResponse<T> {
891
- status: number;
892
- data: T;
890
+ /** Platforms accepted by the news endpoints (aliases pc, playstation, xbox also work). */
891
+ export type NewsPlatform = "Windows" | "Mac" | "PS4" | "PS5" | "XboxOneGDK" | "XSX" | "Switch" | "Switch2" | "Android" | "IOS";
892
+ export interface NewsImage {
893
+ width: number;
894
+ height: number;
895
+ url: string;
896
+ }
897
+ /**
898
+ * A call-to-action button. `action` is "shop" (see `offerId`), "island" (see `linkId`: an
899
+ * island code like "0017-2877-1308" or a playlist id like "playlist_juno"), or Epic's raw
900
+ * action type when it is neither.
901
+ */
902
+ export interface NewsButton {
903
+ text: string | null;
904
+ action: "shop" | "island" | string;
905
+ offerId: string | null;
906
+ linkId: string | null;
893
907
  }
908
+ /** One entry of the lobby news carousel. */
894
909
  export interface MOTD {
895
910
  id: string;
896
- title: string;
897
- body: string;
898
- image: string;
899
- tileImage?: string;
900
- videoURL?: string;
901
- [key: string]: any;
902
- }
903
- export interface BRNews {
911
+ position: number;
912
+ /** Full-screen title. */
913
+ title: string | null;
914
+ /** Full-screen body text. */
915
+ body: string | null;
916
+ /** Title shown on the carousel tile. */
917
+ tileTitle: string | null;
918
+ /** Largest full-screen image. */
919
+ image: string | null;
920
+ /** Largest tile image. */
921
+ tileImage: string | null;
922
+ images: NewsImage[];
923
+ tileImages: NewsImage[];
924
+ buttons: NewsButton[];
925
+ contentHash: string | null;
926
+ }
927
+ /** The lobby news carousel for one mode, as a generic account sees it. */
928
+ export interface NewsFeed {
929
+ mode: "br" | "stw" | "creative" | "festival";
930
+ /** Epic product tag queried, e.g. "Product.BR". */
931
+ tag: string;
932
+ language: string;
933
+ platform: NewsPlatform;
934
+ fetchedAt: string;
904
935
  motds: MOTD[];
905
- platform_motds?: MOTD[];
906
- [key: string]: any;
907
936
  }
908
- export interface STWNews {
909
- motds: MOTD[];
910
- [key: string]: any;
911
- }
912
- export interface CreativeNews {
913
- motds: MOTD[];
914
- [key: string]: any;
937
+ /** An in-game emergency notice banner. */
938
+ export interface NewsNotice {
939
+ title: string | null;
940
+ body: string | null;
941
+ /** Playlists or experiences the notice is shown in. */
942
+ playlists: string[];
943
+ /** When present, the notice is limited to these platforms. */
944
+ platforms: string[] | null;
915
945
  }
916
946
  export interface AllNews {
917
- br: BRNews;
918
- stw: STWNews;
919
- creative: CreativeNews;
920
- lastModified: string;
921
- }
947
+ br: NewsFeed;
948
+ stw: NewsFeed;
949
+ creative: NewsFeed;
950
+ festival: NewsFeed;
951
+ notices: NewsNotice[];
952
+ }
953
+ /** @deprecated The API never wrapped news in { status, data }; this is now just `T`. */
954
+ export type NewsResponse<T> = T;
955
+ /** @deprecated Use NewsFeed. */
956
+ export type BRNews = NewsFeed;
957
+ /** @deprecated Use NewsFeed. */
958
+ export type STWNews = NewsFeed;
959
+ /** @deprecated Use NewsFeed. */
960
+ export type CreativeNews = NewsFeed;
922
961
  export interface CosmeticsResponse<T> {
923
962
  status: number;
924
963
  data: T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaelouuu/fortnite-api",
3
- "version": "9.1.1",
3
+ "version": "9.2.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",