upload-post 2.4.0 → 2.6.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
@@ -321,6 +321,38 @@ These options work across all upload methods:
321
321
  | `autogenerateLanguage` | Force the AI output language (ISO code); omit to auto-detect from the media |
322
322
  | `idempotencyKey` | Collapses duplicate uploads within 24h. Reuse the same value when retrying. Alias: `requestId` |
323
323
 
324
+ ## Google Business Profile
325
+
326
+ Pass the target location on the upload itself. There is no separate "select a location" call — the API resolves the location per post.
327
+
328
+ ```javascript
329
+ const { locations } = await client.getGoogleBusinessLocations('myprofile');
330
+
331
+ await client.upload('video.mp4', {
332
+ user: 'myprofile',
333
+ platforms: ['google_business'],
334
+ title: 'Now open on Sundays',
335
+ gbpLocationId: locations[0].name, // "accounts/123/locations/456"
336
+ });
337
+ ```
338
+
339
+ `gbpLocationId` is **required when the account has more than one location** — the API only auto-selects when exactly one exists. Beyond a standard post you can publish an event or an offer:
340
+
341
+ ```javascript
342
+ await client.uploadText({
343
+ user: 'myprofile',
344
+ platforms: ['google_business'],
345
+ title: 'Summer sale',
346
+ gbpLocationId: locations[0].name,
347
+ gbpTopicType: 'OFFER',
348
+ gbpOfferCoupon: 'SUMMER25',
349
+ gbpOfferRedeemUrl: 'https://example.com/redeem',
350
+ gbpOfferTerms: 'One per customer',
351
+ });
352
+ ```
353
+
354
+ Also available: `gbpTopicType: 'EVENT'` with `gbpEventTitle` / `gbpEventStartDate` / `gbpEventStartTime` / `gbpEventEndDate` / `gbpEventEndTime`, a call-to-action via `gbpCtaType` + `gbpCtaUrl`, and `gbpMediaUrl` / `gbpMediaFormat`.
355
+
324
356
  ## Retrying an upload safely
325
357
 
326
358
  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.
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' | 'reddit' | 'bluesky' | 'x' | 'google_business' | 'discord' | 'telegram';
5
+ export type VideoPlatform = 'tiktok' | 'instagram' | 'youtube' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'reddit' | 'bluesky' | 'x' | 'google_business' | 'discord' | 'telegram' | 'mastodon' | 'wordpress';
6
6
 
7
7
  /** Supported platforms for photo upload */
8
- export type PhotoPlatform = 'tiktok' | 'instagram' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'reddit' | 'bluesky' | 'x' | 'google_business' | 'discord' | 'telegram';
8
+ export type PhotoPlatform = 'tiktok' | 'instagram' | 'linkedin' | 'facebook' | 'pinterest' | 'threads' | 'reddit' | 'bluesky' | 'x' | 'google_business' | 'discord' | 'telegram' | 'mastodon' | 'lemmy' | 'wordpress';
9
9
 
10
10
  /** Supported platforms for text upload */
11
- export type TextPlatform = 'x' | 'linkedin' | 'facebook' | 'threads' | 'reddit' | 'bluesky' | 'google_business' | 'discord' | 'telegram';
11
+ export type TextPlatform = 'x' | 'linkedin' | 'facebook' | 'threads' | 'reddit' | 'bluesky' | 'google_business' | 'discord' | 'telegram' | 'slack' | 'mastodon' | 'nostr' | 'lemmy' | 'devto' | 'hashnode' | 'wordpress' | 'whop' | 'listmonk';
12
12
 
13
13
  /** TikTok privacy levels */
14
14
  export type TikTokPrivacyLevel = 'PUBLIC_TO_EVERYONE' | 'MUTUAL_FOLLOW_FRIENDS' | 'FOLLOWER_OF_CREATOR' | 'SELF_ONLY';
@@ -87,6 +87,15 @@ declare module 'upload-post' {
87
87
  youtubeTitle?: string;
88
88
  pinterestTitle?: string;
89
89
  threadsTitle?: string;
90
+ slackTitle?: string;
91
+ mastodonTitle?: string;
92
+ nostrTitle?: string;
93
+ lemmyTitle?: string;
94
+ devtoTitle?: string;
95
+ hashnodeTitle?: string;
96
+ wordpressTitle?: string;
97
+ whopTitle?: string;
98
+ listmonkTitle?: string;
90
99
 
91
100
  // Platform-specific description overrides
92
101
  description?: string;
@@ -349,6 +358,37 @@ declare module 'upload-post' {
349
358
 
350
359
  // ==================== Combined Upload Options ====================
351
360
 
361
+ export interface GoogleBusinessOptions {
362
+ /** Google Business location id, e.g. "accounts/123/locations/456". Required when the account has more than one location; the API auto-selects only for single-location accounts. List them with getGoogleBusinessLocations(). */
363
+ gbpLocationId?: string;
364
+ /** Post type. Defaults to STANDARD. */
365
+ gbpTopicType?: 'STANDARD' | 'EVENT' | 'OFFER';
366
+ /** Media URL attached to the post */
367
+ gbpMediaUrl?: string;
368
+ /** Media format */
369
+ gbpMediaFormat?: 'PHOTO' | 'VIDEO';
370
+ /** Call-to-action button */
371
+ gbpCtaType?: 'BOOK' | 'ORDER' | 'SHOP' | 'LEARN_MORE' | 'SIGN_UP' | 'CALL';
372
+ /** URL the call-to-action button opens */
373
+ gbpCtaUrl?: string;
374
+ /** Event title. Used when gbpTopicType is EVENT. */
375
+ gbpEventTitle?: string;
376
+ /** Event start date, YYYY-MM-DD */
377
+ gbpEventStartDate?: string;
378
+ /** Event start time, HH:MM */
379
+ gbpEventStartTime?: string;
380
+ /** Event end date, YYYY-MM-DD */
381
+ gbpEventEndDate?: string;
382
+ /** Event end time, HH:MM */
383
+ gbpEventEndTime?: string;
384
+ /** Offer coupon code. Used when gbpTopicType is OFFER. */
385
+ gbpOfferCoupon?: string;
386
+ /** URL to redeem the offer */
387
+ gbpOfferRedeemUrl?: string;
388
+ /** Offer terms and conditions */
389
+ gbpOfferTerms?: string;
390
+ }
391
+
352
392
  export interface UploadVideoOptions extends CommonUploadOptions,
353
393
  TikTokVideoOptions,
354
394
  InstagramVideoOptions,
@@ -357,7 +397,9 @@ declare module 'upload-post' {
357
397
  FacebookVideoOptions,
358
398
  PinterestVideoOptions,
359
399
  XMediaOptions,
360
- ThreadsOptions {
400
+ ThreadsOptions,
401
+ RedditOptions,
402
+ GoogleBusinessOptions {
361
403
  /** Target platforms */
362
404
  platforms: VideoPlatform[];
363
405
  }
@@ -370,7 +412,8 @@ declare module 'upload-post' {
370
412
  PinterestPhotoOptions,
371
413
  XMediaOptions,
372
414
  ThreadsOptions,
373
- RedditOptions {
415
+ RedditOptions,
416
+ GoogleBusinessOptions {
374
417
  /** Target platforms */
375
418
  platforms: PhotoPlatform[];
376
419
  }
@@ -390,7 +433,8 @@ declare module 'upload-post' {
390
433
  XTextOptions,
391
434
  ThreadsOptions,
392
435
  RedditOptions,
393
- LinkPreviewOptions {
436
+ LinkPreviewOptions,
437
+ GoogleBusinessOptions {
394
438
  /** Target platforms */
395
439
  platforms: TextPlatform[];
396
440
  }
@@ -721,7 +765,19 @@ declare module 'upload-post' {
721
765
  * Update notification configuration (including webhook settings)
722
766
  * @param options - Notification config options
723
767
  */
724
- updateNotificationConfig(options?: { webhookEvents?: string[]; webhookUrl?: string }): Promise<{ success: boolean; config?: { webhook_events?: string[]; webhook_url?: string; [key: string]: any } }>;
768
+ updateNotificationConfig(options?: {
769
+ webhookEvents?: string[];
770
+ webhookUrl?: string;
771
+ channels?: string[];
772
+ telegramChatId?: string;
773
+ slackWebhookUrl?: string;
774
+ whatsappToPhone?: string;
775
+ }): Promise<{ success: boolean; config?: { webhook_events?: string[]; webhook_url?: string; [key: string]: any } }>;
776
+
777
+ /**
778
+ * Send a test notification through the configured channels
779
+ */
780
+ testNotifications(): Promise<{ success: boolean; [key: string]: any }>;
725
781
 
726
782
  // Instagram Comments
727
783
 
package/index.js CHANGED
@@ -104,6 +104,16 @@ export class UploadPost {
104
104
  if (options.youtubeTitle) form.append('youtube_title', options.youtubeTitle);
105
105
  if (options.pinterestTitle) form.append('pinterest_title', options.pinterestTitle);
106
106
  if (options.threadsTitle) form.append('threads_title', options.threadsTitle);
107
+ // New credential-based platforms
108
+ if (options.slackTitle) form.append('slack_title', options.slackTitle);
109
+ if (options.mastodonTitle) form.append('mastodon_title', options.mastodonTitle);
110
+ if (options.nostrTitle) form.append('nostr_title', options.nostrTitle);
111
+ if (options.lemmyTitle) form.append('lemmy_title', options.lemmyTitle);
112
+ if (options.devtoTitle) form.append('devto_title', options.devtoTitle);
113
+ if (options.hashnodeTitle) form.append('hashnode_title', options.hashnodeTitle);
114
+ if (options.wordpressTitle) form.append('wordpress_title', options.wordpressTitle);
115
+ if (options.whopTitle) form.append('whop_title', options.whopTitle);
116
+ if (options.listmonkTitle) form.append('listmonk_title', options.listmonkTitle);
107
117
 
108
118
  // Platform-specific description overrides
109
119
  if (options.description) form.append('description', options.description);
@@ -333,6 +343,30 @@ export class UploadPost {
333
343
  if (options.threadsTopicTag) form.append('threads_topic_tag', options.threadsTopicTag);
334
344
  }
335
345
 
346
+ /**
347
+ * Add Google Business Profile parameters
348
+ *
349
+ * gbpLocationId is required for accounts with more than one location; the API
350
+ * only auto-selects when exactly one location exists.
351
+ * @private
352
+ */
353
+ _addGoogleBusinessParams(form, options) {
354
+ if (options.gbpLocationId) form.append('gbp_location_id', options.gbpLocationId);
355
+ if (options.gbpTopicType) form.append('gbp_topic_type', String(options.gbpTopicType).toUpperCase());
356
+ if (options.gbpMediaUrl) form.append('gbp_media_url', options.gbpMediaUrl);
357
+ if (options.gbpMediaFormat) form.append('gbp_media_format', String(options.gbpMediaFormat).toUpperCase());
358
+ if (options.gbpCtaType) form.append('gbp_cta_type', String(options.gbpCtaType).toUpperCase());
359
+ if (options.gbpCtaUrl) form.append('gbp_cta_url', options.gbpCtaUrl);
360
+ if (options.gbpEventTitle) form.append('gbp_event_title', options.gbpEventTitle);
361
+ if (options.gbpEventStartDate) form.append('gbp_event_start_date', options.gbpEventStartDate);
362
+ if (options.gbpEventStartTime) form.append('gbp_event_start_time', options.gbpEventStartTime);
363
+ if (options.gbpEventEndDate) form.append('gbp_event_end_date', options.gbpEventEndDate);
364
+ if (options.gbpEventEndTime) form.append('gbp_event_end_time', options.gbpEventEndTime);
365
+ if (options.gbpOfferCoupon) form.append('gbp_offer_coupon', options.gbpOfferCoupon);
366
+ if (options.gbpOfferRedeemUrl) form.append('gbp_offer_redeem_url', options.gbpOfferRedeemUrl);
367
+ if (options.gbpOfferTerms) form.append('gbp_offer_terms', options.gbpOfferTerms);
368
+ }
369
+
336
370
  /**
337
371
  * Add Reddit-specific parameters
338
372
  * @private
@@ -457,6 +491,7 @@ export class UploadPost {
457
491
  if (platforms.includes('x')) this._addXParams(form, options, false);
458
492
  if (platforms.includes('threads')) this._addThreadsParams(form, options);
459
493
  if (platforms.includes('reddit')) this._addRedditParams(form, options);
494
+ if (platforms.includes('google_business')) this._addGoogleBusinessParams(form, options);
460
495
 
461
496
  return this._request('/upload', 'POST', form, true, this._idempotencyHeaders(options));
462
497
  }
@@ -545,6 +580,7 @@ export class UploadPost {
545
580
  if (platforms.includes('x')) this._addXParams(form, options, false);
546
581
  if (platforms.includes('threads')) this._addThreadsParams(form, options);
547
582
  if (platforms.includes('reddit')) this._addRedditParams(form, options);
583
+ if (platforms.includes('google_business')) this._addGoogleBusinessParams(form, options);
548
584
 
549
585
  return this._request('/upload_photos', 'POST', form, true, this._idempotencyHeaders(options));
550
586
  }
@@ -612,6 +648,7 @@ export class UploadPost {
612
648
  if (platforms.includes('bluesky') && (options.blueskyLinkUrl || options.linkUrl)) {
613
649
  form.append('bluesky_link_url', options.blueskyLinkUrl || options.linkUrl);
614
650
  }
651
+ if (platforms.includes('google_business')) this._addGoogleBusinessParams(form, options);
615
652
 
616
653
  return this._request('/upload_text', 'POST', form, true, this._idempotencyHeaders(options));
617
654
  }
@@ -967,9 +1004,22 @@ export class UploadPost {
967
1004
  const body = {};
968
1005
  if (options.webhookEvents) body.webhook_events = options.webhookEvents;
969
1006
  if (options.webhookUrl) body.webhook_url = options.webhookUrl;
1007
+ if (options.channels) body.channels = options.channels;
1008
+ if (options.telegramChatId) body.telegram_chat_id = options.telegramChatId;
1009
+ if (options.slackWebhookUrl) body.slack_webhook_url = options.slackWebhookUrl;
1010
+ if (options.whatsappToPhone) body.whatsapp_to_phone = options.whatsappToPhone;
970
1011
  return this._request('/uploadposts/users/notifications', 'POST', body);
971
1012
  }
972
1013
 
1014
+ /**
1015
+ * Send a test notification through the configured channels
1016
+ *
1017
+ * @returns {Promise<Object>} Test result
1018
+ */
1019
+ async testNotifications() {
1020
+ return this._request('/uploadposts/users/notifications/test', 'POST', {});
1021
+ }
1022
+
973
1023
  // ==================== Instagram Comments ====================
974
1024
 
975
1025
  /**
@@ -1077,10 +1127,11 @@ export class UploadPost {
1077
1127
  * @param {string} [profile] - Profile username
1078
1128
  * @returns {Promise<Object>} Selection result with google_business_id and display_name
1079
1129
  */
1080
- async selectGoogleBusinessLocation(locationId, profile) {
1081
- const data = { location_id: locationId };
1082
- if (profile) data.profile = profile;
1083
- return this._request('/uploadposts/google-business/locations/select', 'POST', data);
1130
+ async selectGoogleBusinessLocation() {
1131
+ throw new Error(
1132
+ 'selectGoogleBusinessLocation is not supported: the API has no persistent location selection. ' +
1133
+ 'Pass gbpLocationId on the upload instead (list ids with getGoogleBusinessLocations).'
1134
+ );
1084
1135
  }
1085
1136
  }
1086
1137
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upload-post",
3
- "version": "2.4.0",
3
+ "version": "2.6.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",