upload-post 2.2.0 → 2.4.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.
@@ -19,7 +19,7 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  permissions:
21
21
  contents: read
22
- id-token: write
22
+ id-token: write # mints the OIDC token npm trades for publish rights
23
23
  steps:
24
24
  - name: Checkout
25
25
  uses: actions/checkout@v4
@@ -27,9 +27,22 @@ jobs:
27
27
  - name: Setup Node.js
28
28
  uses: actions/setup-node@v4
29
29
  with:
30
- node-version: '22'
30
+ node-version: '24'
31
31
  registry-url: 'https://registry.npmjs.org'
32
32
 
33
+ # Trusted publishing needs npm >= 11.5.1, which Node 24 already bundles.
34
+ # Do NOT `npm install -g npm@latest`: it leaves npm's own tree short of
35
+ # `sigstore`, and `--provenance` then dies on it.
36
+ - name: Check npm supports trusted publishing
37
+ run: |
38
+ NPM_VERSION=$(npm --version)
39
+ echo "npm $NPM_VERSION"
40
+ MIN=11.5.1
41
+ if [ "$(printf '%s\n%s\n' "$MIN" "$NPM_VERSION" | sort -V | head -1)" != "$MIN" ]; then
42
+ echo "::error::npm $NPM_VERSION is older than $MIN, which trusted publishing requires"
43
+ exit 1
44
+ fi
45
+
33
46
  - name: Check if version is new
34
47
  id: version_check
35
48
  run: |
@@ -54,14 +67,12 @@ jobs:
54
67
  if: steps.version_check.outputs.new == 'true' || github.event_name == 'workflow_dispatch'
55
68
  run: npm run build --if-present
56
69
 
70
+ # No NODE_AUTH_TOKEN: npm authenticates via the OIDC token, and the
71
+ # trusted publisher is configured on npmjs.com against this repo+workflow.
57
72
  - name: Publish to npm (dry-run)
58
73
  if: ${{ inputs.dry_run == true }}
59
- run: npm publish --access public --dry-run
60
- env:
61
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
74
+ run: npm publish --provenance --access public --dry-run
62
75
 
63
76
  - name: Publish to npm
64
77
  if: (steps.version_check.outputs.new == 'true' && inputs.dry_run != true) || github.event_name == 'release'
65
- run: npm publish --access public
66
- env:
67
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
78
+ run: npm publish --provenance --access public
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Official Node.js client for the [Upload-Post API](https://www.upload-post.com) - Cross-platform social media upload.
4
4
 
5
- Upload videos, photos, text posts, and documents to **TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, and X (Twitter)** with a single API.
5
+ Upload videos, photos, text posts, and documents to **TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, X (Twitter), Discord, and Telegram** with a single API.
6
6
 
7
7
  ## Installation
8
8
 
@@ -29,9 +29,9 @@ console.log(response);
29
29
 
30
30
  ## Features
31
31
 
32
- - ✅ **Video Upload** - TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Bluesky, X
33
- - ✅ **Photo Upload** - TikTok, Instagram, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, X
34
- - ✅ **Text Posts** - X, LinkedIn, Facebook, Threads, Reddit, Bluesky
32
+ - ✅ **Video Upload** - TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Bluesky, X, Discord, Telegram
33
+ - ✅ **Photo Upload** - TikTok, Instagram, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, X, Discord, Telegram
34
+ - ✅ **Text Posts** - X, LinkedIn, Facebook, Threads, Reddit, Bluesky, Discord, Telegram
35
35
  - ✅ **Document Upload** - LinkedIn (PDF, PPT, PPTX, DOC, DOCX)
36
36
  - ✅ **Scheduling** - Schedule posts for later
37
37
  - ✅ **Posting Queue** - Add posts to your configured queue
@@ -169,6 +169,10 @@ await client.deleteUser('old-profile');
169
169
  const jwt = await client.generateJwt('my-profile', {
170
170
  redirectUrl: 'https://yourapp.com/callback',
171
171
  platforms: ['tiktok', 'instagram'],
172
+ // Optional: force the connection page language for this profile.
173
+ // Supported: 'en' | 'es' | 'de' | 'fr' | 'pt'. When omitted, the page
174
+ // auto-detects the visitor's browser language and falls back to English.
175
+ language: 'es',
172
176
  });
173
177
  ```
174
178
 
@@ -312,6 +316,32 @@ These options work across all upload methods:
312
316
  | `addToQueue` | Add to posting queue |
313
317
  | `maxPostsPerSlot` | Max posts per queue slot (overrides profile setting) |
314
318
  | `asyncUpload` | Process asynchronously (default: true) |
319
+ | `autogenerate` | If true, AI generates native per-platform title/description from the media and fills any field left empty |
320
+ | `autogenerateTitle` / `autogenerateDescription` | Generate only the title or only the description with AI |
321
+ | `autogenerateLanguage` | Force the AI output language (ISO code); omit to auto-detect from the media |
322
+ | `idempotencyKey` | Collapses duplicate uploads within 24h. Reuse the same value when retrying. Alias: `requestId` |
323
+
324
+ ## Retrying an upload safely
325
+
326
+ An upload that times out may still have been accepted by the API. Retrying it without an idempotency key publishes the post a second time.
327
+
328
+ Pass the same `idempotencyKey` on every attempt and the API returns the original job instead of creating a new one:
329
+
330
+ ```javascript
331
+ import { randomUUID } from 'crypto';
332
+
333
+ const idempotencyKey = randomUUID(); // generate ONCE, outside the retry loop
334
+
335
+ for (let attempt = 0; attempt < 3; attempt++) {
336
+ try {
337
+ return await client.upload('video.mp4', { user, platforms: ['tiktok'], title, idempotencyKey });
338
+ } catch (err) {
339
+ if (attempt === 2) throw err;
340
+ }
341
+ }
342
+ ```
343
+
344
+ Generating the key inside the loop defeats the mechanism: each attempt would look like a new upload.
315
345
 
316
346
  ## TypeScript Support
317
347
 
package/index.d.ts CHANGED
@@ -2,13 +2,13 @@ declare module 'upload-post' {
2
2
  // ==================== Common Types ====================
3
3
 
4
4
  /** Supported platforms for video upload */
5
- export type VideoPlatform = 'tiktok' | 'instagram' | 'youtube' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'bluesky' | 'x' | 'google_business';
5
+ export type VideoPlatform = 'tiktok' | 'instagram' | 'youtube' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'reddit' | 'bluesky' | 'x' | 'google_business' | 'discord' | 'telegram';
6
6
 
7
7
  /** Supported platforms for photo upload */
8
- export type PhotoPlatform = 'tiktok' | 'instagram' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'reddit' | 'bluesky' | 'x' | 'google_business';
8
+ export type PhotoPlatform = 'tiktok' | 'instagram' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'reddit' | 'bluesky' | 'x' | 'google_business' | 'discord' | 'telegram';
9
9
 
10
10
  /** Supported platforms for text upload */
11
- export type TextPlatform = 'x' | 'linkedin' | 'facebook' | 'threads' | 'reddit' | 'bluesky' | 'google_business';
11
+ export type TextPlatform = 'x' | 'linkedin' | 'facebook' | 'threads' | 'reddit' | 'bluesky' | 'google_business' | 'discord' | 'telegram';
12
12
 
13
13
  /** TikTok privacy levels */
14
14
  export type TikTokPrivacyLevel = 'PUBLIC_TO_EVERYONE' | 'MUTUAL_FOLLOW_FRIENDS' | 'FOLLOWER_OF_CREATOR' | 'SELF_ONLY';
@@ -45,6 +45,13 @@ declare module 'upload-post' {
45
45
  export interface CommonUploadOptions {
46
46
  /** Post title/caption. Required for YouTube, Reddit, and text posts. Optional for TikTok, Instagram, Facebook, LinkedIn, X, Threads, Bluesky, Pinterest. */
47
47
  title?: string;
48
+ /**
49
+ * Key the API uses to collapse duplicate uploads within a 24-hour window.
50
+ * Pass the same value when retrying a failed upload, otherwise the retry publishes a second post.
51
+ */
52
+ idempotencyKey?: string;
53
+ /** Alias for {@link CommonUploadOptions.idempotencyKey}. */
54
+ requestId?: string;
48
55
  /** User identifier (profile name) */
49
56
  user: string;
50
57
  /** First comment to post after publishing */
@@ -61,6 +68,14 @@ declare module 'upload-post' {
61
68
  maxPostsPerSlot?: number;
62
69
  /** Process upload asynchronously (default: true) */
63
70
  asyncUpload?: boolean;
71
+ /** If true, AI generates native per-platform title/description from the media and fills any field left empty */
72
+ autogenerate?: boolean;
73
+ /** Generate only the title with AI */
74
+ autogenerateTitle?: boolean;
75
+ /** Generate only the description with AI */
76
+ autogenerateDescription?: boolean;
77
+ /** Force the AI output language (ISO code); omit to auto-detect from the media */
78
+ autogenerateLanguage?: string;
64
79
 
65
80
  // Platform-specific title overrides
66
81
  blueskyTitle?: string;
@@ -192,6 +207,8 @@ declare module 'upload-post' {
192
207
  youtubeHasPaidProductPlacement?: boolean;
193
208
  /** Recording date (ISO 8601) */
194
209
  youtubeRecordingDate?: string;
210
+ /** Playlist ID(s) to add the uploaded video to — one ID, an array, or a comma-separated list */
211
+ youtubePlaylistId?: string | string[];
195
212
  /** Subtitle/caption files to upload. Each entry needs a language code and either a file path or URL. */
196
213
  youtubeSubtitles?: Array<{
197
214
  /** BCP-47 language code (e.g. "en", "es") */
@@ -317,6 +334,8 @@ declare module 'upload-post' {
317
334
  threadsLongTextAsPost?: boolean;
318
335
  /** Comma-separated list of how many media items per Threads post (e.g. "5,5"). Each value 1-10, total must equal file count. */
319
336
  threadsThreadMediaLayout?: string;
337
+ /** Topic tag for the Threads post */
338
+ threadsTopicTag?: string;
320
339
  }
321
340
 
322
341
  // ==================== Reddit Options ====================
@@ -482,7 +501,7 @@ declare module 'upload-post' {
482
501
  * Upload-Post API client
483
502
  *
484
503
  * Supports uploading to: TikTok, Instagram, YouTube, LinkedIn, Facebook,
485
- * Pinterest, Threads, Reddit, Bluesky, X (Twitter)
504
+ * Pinterest, Threads, Reddit, Bluesky, X (Twitter), Discord, Telegram
486
505
  */
487
506
  export class UploadPost {
488
507
  /**
@@ -673,6 +692,7 @@ declare module 'upload-post' {
673
692
  readonlyCalendar?: boolean;
674
693
  connectTitle?: string;
675
694
  connectDescription?: string;
695
+ language?: 'en' | 'es' | 'de' | 'fr' | 'pt';
676
696
  }): Promise<JwtResponse>;
677
697
 
678
698
  /**
@@ -761,6 +781,26 @@ declare module 'upload-post' {
761
781
  * @param profile - Profile username
762
782
  */
763
783
  getPinterestBoards(profile?: string): Promise<BoardsResponse>;
784
+
785
+ /**
786
+ * Get analytics for a post published outside Upload-Post, by its native platform ID
787
+ * @param platformPostId - The post ID assigned by the platform
788
+ * @param platform - Platform the post lives on
789
+ * @param user - Profile username that owns the connected account
790
+ */
791
+ getPostAnalyticsByPlatformId(platformPostId: string, platform: string, user: string): Promise<Record<string, unknown>>;
792
+
793
+ /**
794
+ * Get detailed Reddit posts with full media information
795
+ * @param profileUsername - Profile username
796
+ */
797
+ getRedditDetailedPosts(profileUsername: string): Promise<Record<string, unknown>>;
798
+
799
+ /**
800
+ * Get available Google Business locations for a profile
801
+ * @param profile - Profile username
802
+ */
803
+ getGoogleBusinessLocations(profile?: string): Promise<Record<string, unknown>>;
764
804
  }
765
805
 
766
806
  export default UploadPost;
package/index.js CHANGED
@@ -8,8 +8,8 @@ const API_BASE_URL = 'https://api.upload-post.com/api';
8
8
  /**
9
9
  * Upload-Post API client
10
10
  *
11
- * Supports uploading to: TikTok, Instagram, YouTube, LinkedIn, Facebook,
12
- * Pinterest, Threads, Reddit, Bluesky, X (Twitter)
11
+ * Supports uploading to: TikTok, Instagram, YouTube, LinkedIn, Facebook,
12
+ * Pinterest, Threads, Reddit, Bluesky, X (Twitter), Discord, Telegram
13
13
  */
14
14
  export class UploadPost {
15
15
  /**
@@ -24,13 +24,14 @@ export class UploadPost {
24
24
  * Make an API request
25
25
  * @private
26
26
  */
27
- async _request(endpoint, method = 'GET', data = null, isFormData = false) {
27
+ async _request(endpoint, method = 'GET', data = null, isFormData = false, extraHeaders = {}) {
28
28
  const config = {
29
29
  method,
30
30
  url: `${this.baseUrl}${endpoint}`,
31
31
  headers: {
32
32
  'Authorization': `Apikey ${this.apiKey}`,
33
33
  'X-Upload-Post-Source': 'npm',
34
+ ...extraHeaders,
34
35
  },
35
36
  maxContentLength: Infinity,
36
37
  maxBodyLength: Infinity
@@ -57,6 +58,16 @@ export class UploadPost {
57
58
  }
58
59
  }
59
60
 
61
+ /**
62
+ * The API collapses two uploads carrying the same key within 24 hours into a
63
+ * single post. Retrying an upload without one publishes it twice.
64
+ * @private
65
+ */
66
+ _idempotencyHeaders(options) {
67
+ const key = options.idempotencyKey || options.requestId;
68
+ return key ? { 'Idempotency-Key': String(key) } : {};
69
+ }
70
+
60
71
  /**
61
72
  * Add common upload parameters to form
62
73
  * @private
@@ -77,6 +88,11 @@ export class UploadPost {
77
88
  if (options.addToQueue !== undefined) form.append('add_to_queue', String(options.addToQueue));
78
89
  if (options.maxPostsPerSlot !== undefined) form.append('max_posts_per_slot', String(options.maxPostsPerSlot));
79
90
  if (options.asyncUpload !== undefined) form.append('async_upload', String(options.asyncUpload));
91
+ // AI auto-generation of native per-platform copy from the media (fills blank fields)
92
+ if (options.autogenerate !== undefined) form.append('autogenerate', String(options.autogenerate));
93
+ if (options.autogenerateTitle !== undefined) form.append('autogenerate_title', String(options.autogenerateTitle));
94
+ if (options.autogenerateDescription !== undefined) form.append('autogenerate_description', String(options.autogenerateDescription));
95
+ if (options.autogenerateLanguage) form.append('autogenerate_language', String(options.autogenerateLanguage));
80
96
 
81
97
  // Platform-specific title overrides
82
98
  if (options.blueskyTitle) form.append('bluesky_title', options.blueskyTitle);
@@ -198,6 +214,12 @@ export class UploadPost {
198
214
  if (options.youtubeBlockedCountries) form.append('blockedCountries', options.youtubeBlockedCountries);
199
215
  if (options.youtubeHasPaidProductPlacement !== undefined) form.append('hasPaidProductPlacement', String(options.youtubeHasPaidProductPlacement));
200
216
  if (options.youtubeRecordingDate) form.append('recordingDate', options.youtubeRecordingDate);
217
+ if (options.youtubePlaylistId) {
218
+ const playlistIds = Array.isArray(options.youtubePlaylistId)
219
+ ? options.youtubePlaylistId.join(',')
220
+ : options.youtubePlaylistId;
221
+ form.append('youtube_playlist_id', playlistIds);
222
+ }
201
223
  if (options.youtubeSubtitles && Array.isArray(options.youtubeSubtitles)) {
202
224
  options.youtubeSubtitles.forEach((sub, idx) => {
203
225
  if (sub.language) {
@@ -330,7 +352,7 @@ export class UploadPost {
330
352
  * @param {Object} options - Upload options
331
353
  * @param {string} options.title - Video title/caption
332
354
  * @param {string} options.user - User identifier (profile name)
333
- * @param {string[]} options.platforms - Target platforms (tiktok, instagram, youtube, linkedin, facebook, pinterest, threads, bluesky, x)
355
+ * @param {string[]} options.platforms - Target platforms (tiktok, instagram, youtube, linkedin, facebook, pinterest, threads, bluesky, x, discord, telegram)
334
356
  * @param {string} [options.description] - Video description
335
357
  * @param {string} [options.firstComment] - First comment to post
336
358
  * @param {string} [options.scheduledDate] - ISO date for scheduling (e.g., "2024-12-25T10:00:00Z")
@@ -434,8 +456,9 @@ export class UploadPost {
434
456
  if (platforms.includes('pinterest')) this._addPinterestParams(form, options, true);
435
457
  if (platforms.includes('x')) this._addXParams(form, options, false);
436
458
  if (platforms.includes('threads')) this._addThreadsParams(form, options);
459
+ if (platforms.includes('reddit')) this._addRedditParams(form, options);
437
460
 
438
- return this._request('/upload', 'POST', form, true);
461
+ return this._request('/upload', 'POST', form, true, this._idempotencyHeaders(options));
439
462
  }
440
463
 
441
464
  /**
@@ -445,7 +468,7 @@ export class UploadPost {
445
468
  * @param {Object} options - Upload options
446
469
  * @param {string} options.title - Post title/caption
447
470
  * @param {string} options.user - User identifier (profile name)
448
- * @param {string[]} options.platforms - Target platforms (tiktok, instagram, linkedin, facebook, x, threads, pinterest, reddit, bluesky)
471
+ * @param {string[]} options.platforms - Target platforms (tiktok, instagram, linkedin, facebook, x, threads, pinterest, reddit, bluesky, discord, telegram)
449
472
  * @param {string} [options.description] - Photo description
450
473
  * @param {string} [options.firstComment] - First comment to post
451
474
  * @param {string} [options.altText] - Alt text for accessibility
@@ -523,7 +546,7 @@ export class UploadPost {
523
546
  if (platforms.includes('threads')) this._addThreadsParams(form, options);
524
547
  if (platforms.includes('reddit')) this._addRedditParams(form, options);
525
548
 
526
- return this._request('/upload_photos', 'POST', form, true);
549
+ return this._request('/upload_photos', 'POST', form, true, this._idempotencyHeaders(options));
527
550
  }
528
551
 
529
552
  /**
@@ -532,7 +555,7 @@ export class UploadPost {
532
555
  * @param {Object} options - Upload options
533
556
  * @param {string} options.title - Text content for the post
534
557
  * @param {string} options.user - User identifier (profile name)
535
- * @param {string[]} options.platforms - Target platforms (x, linkedin, facebook, threads, reddit, bluesky)
558
+ * @param {string[]} options.platforms - Target platforms (x, linkedin, facebook, threads, reddit, bluesky, discord, telegram)
536
559
  * @param {string} [options.firstComment] - First comment to post
537
560
  * @param {string} [options.scheduledDate] - ISO date for scheduling
538
561
  * @param {string} [options.timezone] - Timezone for scheduled date
@@ -590,7 +613,7 @@ export class UploadPost {
590
613
  form.append('bluesky_link_url', options.blueskyLinkUrl || options.linkUrl);
591
614
  }
592
615
 
593
- return this._request('/upload_text', 'POST', form, true);
616
+ return this._request('/upload_text', 'POST', form, true, this._idempotencyHeaders(options));
594
617
  }
595
618
 
596
619
  /**
@@ -634,10 +657,15 @@ export class UploadPost {
634
657
  if (options.addToQueue !== undefined) form.append('add_to_queue', String(options.addToQueue));
635
658
  if (options.maxPostsPerSlot !== undefined) form.append('max_posts_per_slot', String(options.maxPostsPerSlot));
636
659
  if (options.asyncUpload !== undefined) form.append('async_upload', String(options.asyncUpload));
660
+ // AI auto-generation of native per-platform copy from the media (fills blank fields)
661
+ if (options.autogenerate !== undefined) form.append('autogenerate', String(options.autogenerate));
662
+ if (options.autogenerateTitle !== undefined) form.append('autogenerate_title', String(options.autogenerateTitle));
663
+ if (options.autogenerateDescription !== undefined) form.append('autogenerate_description', String(options.autogenerateDescription));
664
+ if (options.autogenerateLanguage) form.append('autogenerate_language', String(options.autogenerateLanguage));
637
665
 
638
666
  this._addLinkedinParams(form, options);
639
667
 
640
- return this._request('/upload_document', 'POST', form, true);
668
+ return this._request('/upload_document', 'POST', form, true, this._idempotencyHeaders(options));
641
669
  }
642
670
 
643
671
  // ==================== Status & History ====================
@@ -762,6 +790,16 @@ export class UploadPost {
762
790
  return this._request('/uploadposts/platform-metrics', 'GET');
763
791
  }
764
792
 
793
+ /**
794
+ * Get detailed Reddit posts with full media information
795
+ *
796
+ * @param {string} profileUsername - Profile username
797
+ * @returns {Promise<Object>} Detailed Reddit posts
798
+ */
799
+ async getRedditDetailedPosts(profileUsername) {
800
+ return this._request('/uploadposts/reddit/detailed-posts/', 'GET', { profile_username: profileUsername });
801
+ }
802
+
765
803
  /**
766
804
  * Get recent media from a connected social account.
767
805
  *
@@ -811,7 +849,7 @@ export class UploadPost {
811
849
  const body = {};
812
850
  if (options.scheduledDate) body.scheduled_date = options.scheduledDate;
813
851
  if (options.timezone) body.timezone = options.timezone;
814
- return this._request(`/uploadposts/schedule/${jobId}`, 'POST', body);
852
+ return this._request(`/uploadposts/schedule/${jobId}`, 'PATCH', body);
815
853
  }
816
854
 
817
855
  // ==================== User Management ====================
@@ -859,6 +897,7 @@ export class UploadPost {
859
897
  * @param {boolean} [options.readonlyCalendar] - Show only a read-only calendar (no editing, no account connection)
860
898
  * @param {string} [options.connectTitle] - Custom title for the connection page
861
899
  * @param {string} [options.connectDescription] - Custom description for the connection page
900
+ * @param {('en'|'es'|'de'|'fr'|'pt')} [options.language] - Force the connection page language for this profile. When omitted, the page auto-detects the visitor's browser language and falls back to English.
862
901
  * @returns {Promise<Object>} JWT and connection URL
863
902
  */
864
903
  async generateJwt(username, options = {}) {
@@ -871,6 +910,7 @@ export class UploadPost {
871
910
  if (options.readonlyCalendar !== undefined) body.readonly_calendar = options.readonlyCalendar;
872
911
  if (options.connectTitle) body.connect_title = options.connectTitle;
873
912
  if (options.connectDescription) body.connect_description = options.connectDescription;
913
+ if (options.language) body.language = options.language;
874
914
  return this._request('/uploadposts/users/generate-jwt', 'POST', body);
875
915
  }
876
916
 
@@ -881,7 +921,7 @@ export class UploadPost {
881
921
  * @returns {Promise<Object>} Validation result
882
922
  */
883
923
  async validateJwt(jwt) {
884
- return this._request('/uploadposts/users/validate-jwt', 'POST', { jwt });
924
+ return this._request('/uploadposts/users/validate-jwt', 'GET', null, false, { Authorization: `Bearer ${jwt}` });
885
925
  }
886
926
 
887
927
  /**
@@ -912,7 +952,7 @@ export class UploadPost {
912
952
  * @returns {Promise<Object>} Notification config
913
953
  */
914
954
  async getNotificationConfig() {
915
- return this._request('/uploadposts/notification-config', 'GET');
955
+ return this._request('/uploadposts/users/notifications', 'GET');
916
956
  }
917
957
 
918
958
  /**
@@ -927,7 +967,7 @@ export class UploadPost {
927
967
  const body = {};
928
968
  if (options.webhookEvents) body.webhook_events = options.webhookEvents;
929
969
  if (options.webhookUrl) body.webhook_url = options.webhookUrl;
930
- return this._request('/uploadposts/notification-config', 'POST', body);
970
+ return this._request('/uploadposts/users/notifications', 'POST', body);
931
971
  }
932
972
 
933
973
  // ==================== Instagram Comments ====================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upload-post",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Official client library for Upload-Post API - Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, and X (Twitter)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",