n8n-nodes-upload-post 0.1.55 → 0.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
|
@@ -77,6 +77,11 @@ The node provides the following operations grouped for clarity:
|
|
|
77
77
|
- Parameters: Request ID, Platform (optional filter).
|
|
78
78
|
- **Get Post Analytics by Platform ID**: Per-post metrics for a post published outside Upload-Post.
|
|
79
79
|
- Parameters: Platform Post ID, Platform, Profile Username.
|
|
80
|
+
- **Get Cached Post Analytics**: Replays per-post metrics already fetched, instead of querying the platforms again, so it is not subject to the live analytics rate limit (100 requests / 5 minutes). Only contains posts previously fetched through a live per-post endpoint; there is no background refresh, so captured_at is the last time that post was read live.
|
|
81
|
+
- Parameters: Profile Username (required), Platform (optional filter), Limit (default 50, max 200), Cursor, Since / Until (`YYYY-MM-DD`, defaults to the last 30 days).
|
|
82
|
+
- Values are only as fresh as your last live read — check `captured_at` on each post. Use **Get Post Analytics** for a just-published post and this operation for bulk or historical reads.
|
|
83
|
+
- Paginate by passing the `next_cursor` from the previous response as `Cursor` while `has_more` is true.
|
|
84
|
+
- Supported: Facebook, Instagram, LinkedIn, Pinterest, Reddit, Threads, TikTok, YouTube. X (Twitter) is not cached.
|
|
80
85
|
- **Get Total Impressions**: Impressions aggregated across connected platforms.
|
|
81
86
|
- Parameters: Profile Username, Period or Start/End Date, Platforms, Breakdown.
|
|
82
87
|
- **Get Platform Metrics**: Lists which metrics each platform exposes.
|
|
@@ -102,9 +107,12 @@ The node provides the following operations grouped for clarity:
|
|
|
102
107
|
- **Delete User**: Delete an existing user profile.
|
|
103
108
|
- Parameters: Username to delete.
|
|
104
109
|
- **Generate JWT (for platform integration)**: Generate a connection URL (JWT) for a given profile so the user can link social accounts.
|
|
105
|
-
- Parameters: User Identifier, optional redirect URL, logo image URL, redirect button text, platform restrictions.
|
|
110
|
+
- Parameters: User Identifier, optional redirect URL, logo image URL, redirect button text, platform restrictions, calendar options, connect title/description, language, UI labels.
|
|
111
|
+
- **Language**: forces the connection page language. Supported: English, Spanish, German, French, Portuguese, Polish, Turkish. Leave on Auto-Detect to use the visitor's browser language (falls back to English).
|
|
112
|
+
- **UI Labels**: white-label overrides for individual connection page texts, as key/value pairs (sent as `ui_labels`). The key is an i18n dot-path such as `connect.connectButton`, the value the replacement string. The API accepts up to 100 entries, keys matching `^[a-zA-Z0-9_.]+$` and values of up to 300 characters, and rejects the request otherwise.
|
|
106
113
|
- **Validate JWT (for platform integration)**: Validate a connection token from your backend.
|
|
107
114
|
- Parameters: JWT token (password field).
|
|
115
|
+
- The API response is returned as-is; its `profile` object also carries the `ui_labels` map configured for that profile.
|
|
108
116
|
|
|
109
117
|
Refer to the [Upload Post API Documentation](https://docs.upload-post.com) for detailed information on parameters and platform requirements.
|
|
110
118
|
|
|
@@ -160,6 +168,45 @@ If you saw duplicate posts on an older version of this node, upgrade: versions b
|
|
|
160
168
|
- **Video Options**: Privacy level (Public/Mutual Friends/Followers/Self), disable duet/stitch/comments, cover timestamp (ms), brand content toggles, AI-generated content flag, post mode (Direct Post/Media Upload).
|
|
161
169
|
- **Brand Content**: Separate toggles for paid partnerships and own business promotion.
|
|
162
170
|
|
|
171
|
+
#### TikTok Advanced Video Options
|
|
172
|
+
|
|
173
|
+
> **Capability-gated.** `GET /api/uploadposts/users` returns a `capabilities`
|
|
174
|
+
> array on each TikTok account (`music`, `location`, `cover_image`,
|
|
175
|
+
> `cover_timestamp`, `draft`, `photo_privacy`, `video_privacy`,
|
|
176
|
+
> `inbox_fallback`, `profile_analytics`). If the connection does not declare the capability an option
|
|
177
|
+
> needs, the API ignores that field, the post still publishes and the response
|
|
178
|
+
> includes a per-field warning — reconnect the TikTok account to enable it.
|
|
179
|
+
> These options are only sent when actually filled in, so leaving them at their
|
|
180
|
+
> defaults keeps the previous behaviour.
|
|
181
|
+
|
|
182
|
+
- **Music** (`music`): TikTok Music ID — the `id` of a track returned by `GET /api/uploadposts/tiktok/music/trending` or `GET /api/uploadposts/tiktok/music/search` (not its `commercial_music_id`) — plus music volume (0-100) and music start/end offsets in ms. The Music ID works on **video and photo** posts; the volume and the offsets are video-only, because TikTok's photo contract takes the track id alone.
|
|
183
|
+
|
|
184
|
+
To pick a track by name inside a workflow, put an **HTTP Request** node before
|
|
185
|
+
this one calling
|
|
186
|
+
`GET https://api.upload-post.com/api/uploadposts/tiktok/music/search?profile=<profile>&q=<song or artist>`
|
|
187
|
+
with the header `Authorization: Apikey <your key>`, and feed `tracks[0].id`
|
|
188
|
+
into TikTok Music ID. It also accepts `genre`, `country_code`, `date_range`
|
|
189
|
+
and `limit`. Note that TikTok has **no music search endpoint**: the search
|
|
190
|
+
runs over the trending charts Upload-Post caches per genre/country/period, so
|
|
191
|
+
it finds trending tracks, not TikTok's entire catalogue.
|
|
192
|
+
- **Original Sound Volume**: Volume (0-100) of the video's own audio when music is added. Keep it above 0 so the original audio is not muted. Music volume and original sound volume are only sent when a Music ID is set.
|
|
193
|
+
- **Location** (`location`): TikTok Location ID plus TikTok Location Name — TikTok requires both together. Works on video and photo posts.
|
|
194
|
+
- **Cover Image URL** (`cover_image`): Custom cover image, takes priority over the cover timestamp. Video only.
|
|
195
|
+
- **Is AI Generated**: AI-generated content disclosure. Works on video and photo posts.
|
|
196
|
+
- **Upload to Draft** (`draft`): Sends the video to TikTok drafts instead of publishing; TikTok then ignores the rest of the post settings. Video only.
|
|
197
|
+
|
|
198
|
+
> **Privacy level on TikTok.** `privacy_level` is accepted on video and photo
|
|
199
|
+
> uploads alike (capabilities `video_privacy` / `photo_privacy`), but **TikTok
|
|
200
|
+
> decides per account which values are available**: a private account is offered
|
|
201
|
+
> Followers / Mutual Friends / Self Only and has no Public. Asking for one the
|
|
202
|
+
> account does not have fails with `tiktok_privacy_unavailable`, and the error
|
|
203
|
+
> lists the ones it does have. The **Account Default** option on the TikTok
|
|
204
|
+
> Privacy Level (Video) field sends nothing and lets TikTok apply the account's
|
|
205
|
+
> own setting — the only choice guaranteed to work on every account, and the
|
|
206
|
+
> default for new nodes. Photo posts default to Public. To pick a value up front,
|
|
207
|
+
> query `GET /api/uploadposts/tiktok/settings?profile=<profile>` from an HTTP
|
|
208
|
+
> Request node and read `privacy_level_options`.
|
|
209
|
+
|
|
163
210
|
#### YouTube
|
|
164
211
|
- **Video Metadata**: Tags (comma-separated), category ID, privacy status (public/unlisted/private), embeddable, license, public stats viewable.
|
|
165
212
|
- **Compliance**: Made for kids declaration, self-declared made for kids (COPPA), contains synthetic media (AI transparency), has paid product placement (FTC).
|
|
@@ -394,6 +394,20 @@ const applyFacebookOptions = (ctx, operation, formData, isManualPlatform = false
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
};
|
|
397
|
+
const applySharedTiktokFields = (ctx, formData) => {
|
|
398
|
+
const musicId = ctx.node.getNodeParameter('tiktokMusicId', ctx.itemIndex, '');
|
|
399
|
+
if (musicId)
|
|
400
|
+
formData.tiktok_music_id = musicId;
|
|
401
|
+
const locationId = ctx.node.getNodeParameter('tiktokLocationId', ctx.itemIndex, '');
|
|
402
|
+
const locationName = ctx.node.getNodeParameter('tiktokLocationName', ctx.itemIndex, '');
|
|
403
|
+
if (locationId && locationName) {
|
|
404
|
+
formData.tiktok_location_id = locationId;
|
|
405
|
+
formData.tiktok_location_name = locationName;
|
|
406
|
+
}
|
|
407
|
+
const isAiGenerated = ctx.node.getNodeParameter('tiktokIsAiGenerated', ctx.itemIndex, false);
|
|
408
|
+
if (isAiGenerated)
|
|
409
|
+
formData.tiktok_is_ai_generated = 'true';
|
|
410
|
+
};
|
|
397
411
|
const applyTiktokOptions = (ctx, operation, formData) => {
|
|
398
412
|
if (operation === 'uploadPhotos') {
|
|
399
413
|
const autoAddMusic = ctx.node.getNodeParameter('tiktokAutoAddMusic', ctx.itemIndex, false);
|
|
@@ -410,6 +424,7 @@ const applyTiktokOptions = (ctx, operation, formData) => {
|
|
|
410
424
|
if (photoDescription && formData.description === undefined) {
|
|
411
425
|
formData.description = photoDescription;
|
|
412
426
|
}
|
|
427
|
+
applySharedTiktokFields(ctx, formData);
|
|
413
428
|
}
|
|
414
429
|
else if (operation === 'uploadVideo') {
|
|
415
430
|
const privacyLevel = ctx.node.getNodeParameter('tiktokPrivacyLevel', ctx.itemIndex, '');
|
|
@@ -432,6 +447,23 @@ const applyTiktokOptions = (ctx, operation, formData) => {
|
|
|
432
447
|
formData.is_aigc = String(isAigc);
|
|
433
448
|
if (postMode)
|
|
434
449
|
formData.post_mode = postMode;
|
|
450
|
+
applySharedTiktokFields(ctx, formData);
|
|
451
|
+
if (formData.tiktok_music_id) {
|
|
452
|
+
formData.tiktok_music_volume = ctx.node.getNodeParameter('tiktokMusicVolume', ctx.itemIndex, 50);
|
|
453
|
+
formData.tiktok_original_sound_volume = ctx.node.getNodeParameter('tiktokOriginalSoundVolume', ctx.itemIndex, 50);
|
|
454
|
+
const musicStart = ctx.node.getNodeParameter('tiktokMusicStart', ctx.itemIndex, 0);
|
|
455
|
+
const musicEnd = ctx.node.getNodeParameter('tiktokMusicEnd', ctx.itemIndex, 0);
|
|
456
|
+
if (musicStart > 0)
|
|
457
|
+
formData.tiktok_music_start = musicStart;
|
|
458
|
+
if (musicEnd > 0)
|
|
459
|
+
formData.tiktok_music_end = musicEnd;
|
|
460
|
+
}
|
|
461
|
+
const coverImageUrl = ctx.node.getNodeParameter('tiktokCoverImageUrl', ctx.itemIndex, '');
|
|
462
|
+
if (coverImageUrl)
|
|
463
|
+
formData.tiktok_cover_image_url = coverImageUrl;
|
|
464
|
+
const uploadToDraft = ctx.node.getNodeParameter('tiktokUploadToDraft', ctx.itemIndex, false);
|
|
465
|
+
if (uploadToDraft)
|
|
466
|
+
formData.tiktok_upload_to_draft = 'true';
|
|
435
467
|
}
|
|
436
468
|
};
|
|
437
469
|
const applyInstagramOptions = async (ctx, operation, formData) => {
|
|
@@ -694,6 +726,13 @@ const applyGoogleBusinessOptions = (ctx, _operation, formData) => {
|
|
|
694
726
|
const mediaFormat = ctx.node.getNodeParameter('gbpMediaFormat', ctx.itemIndex, '');
|
|
695
727
|
if (mediaFormat)
|
|
696
728
|
formData.gbp_media_format = mediaFormat;
|
|
729
|
+
const postType = ctx.node.getNodeParameter('gbpPostType', ctx.itemIndex, '');
|
|
730
|
+
if (postType) {
|
|
731
|
+
formData.gbp_post_type = postType;
|
|
732
|
+
const mediaCategory = ctx.node.getNodeParameter('gbpMediaCategory', ctx.itemIndex, '');
|
|
733
|
+
if (mediaCategory)
|
|
734
|
+
formData.gbp_media_category = mediaCategory;
|
|
735
|
+
}
|
|
697
736
|
const ctaType = ctx.node.getNodeParameter('gbpCtaType', ctx.itemIndex, '');
|
|
698
737
|
if (ctaType)
|
|
699
738
|
formData.gbp_cta_type = ctaType;
|
|
@@ -965,6 +1004,33 @@ const buildMonitoringRequest = (ctx) => {
|
|
|
965
1004
|
waitForCompletion: false,
|
|
966
1005
|
};
|
|
967
1006
|
}
|
|
1007
|
+
case 'getCachedPostAnalytics': {
|
|
1008
|
+
const qs = {
|
|
1009
|
+
user: ctx.node.getNodeParameter('cachedAnalyticsProfileUsername', ctx.itemIndex),
|
|
1010
|
+
};
|
|
1011
|
+
const platform = ctx.node.getNodeParameter('cachedAnalyticsPlatform', ctx.itemIndex, '');
|
|
1012
|
+
if (platform)
|
|
1013
|
+
qs.platform = platform;
|
|
1014
|
+
const limit = ctx.node.getNodeParameter('cachedAnalyticsLimit', ctx.itemIndex, 50);
|
|
1015
|
+
if (limit)
|
|
1016
|
+
qs.limit = limit;
|
|
1017
|
+
const cursor = ctx.node.getNodeParameter('cachedAnalyticsCursor', ctx.itemIndex, '');
|
|
1018
|
+
if (cursor)
|
|
1019
|
+
qs.cursor = cursor;
|
|
1020
|
+
const since = ctx.node.getNodeParameter('cachedAnalyticsSince', ctx.itemIndex, '');
|
|
1021
|
+
if (since)
|
|
1022
|
+
qs.since = since;
|
|
1023
|
+
const until = ctx.node.getNodeParameter('cachedAnalyticsUntil', ctx.itemIndex, '');
|
|
1024
|
+
if (until)
|
|
1025
|
+
qs.until = until;
|
|
1026
|
+
return {
|
|
1027
|
+
endpoint: '/uploadposts/post-analytics/cached',
|
|
1028
|
+
method: 'GET',
|
|
1029
|
+
qs,
|
|
1030
|
+
isUploadOperation: false,
|
|
1031
|
+
waitForCompletion: false,
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
968
1034
|
case 'getPlatformMetrics': {
|
|
969
1035
|
return {
|
|
970
1036
|
endpoint: '/uploadposts/platform-metrics',
|
|
@@ -1051,6 +1117,19 @@ const buildMonitoringRequest = (ctx) => {
|
|
|
1051
1117
|
});
|
|
1052
1118
|
}
|
|
1053
1119
|
};
|
|
1120
|
+
const collectUiLabels = (ctx) => {
|
|
1121
|
+
var _a, _b;
|
|
1122
|
+
const raw = ctx.node.getNodeParameter('uiLabels', ctx.itemIndex, {});
|
|
1123
|
+
const entries = Array.isArray(raw.label) ? raw.label : [];
|
|
1124
|
+
const uiLabels = {};
|
|
1125
|
+
for (const entry of entries) {
|
|
1126
|
+
const key = String((_a = entry.key) !== null && _a !== void 0 ? _a : '').trim();
|
|
1127
|
+
if (!key)
|
|
1128
|
+
continue;
|
|
1129
|
+
uiLabels[key] = String((_b = entry.value) !== null && _b !== void 0 ? _b : '');
|
|
1130
|
+
}
|
|
1131
|
+
return uiLabels;
|
|
1132
|
+
};
|
|
1054
1133
|
const buildUserRequest = async (ctx) => {
|
|
1055
1134
|
switch (ctx.operation) {
|
|
1056
1135
|
case 'listUsers':
|
|
@@ -1108,6 +1187,9 @@ const buildUserRequest = async (ctx) => {
|
|
|
1108
1187
|
body.connect_description = connectDescription;
|
|
1109
1188
|
if (language)
|
|
1110
1189
|
body.language = language;
|
|
1190
|
+
const uiLabels = collectUiLabels(ctx);
|
|
1191
|
+
if (Object.keys(uiLabels).length > 0)
|
|
1192
|
+
body.ui_labels = uiLabels;
|
|
1111
1193
|
return {
|
|
1112
1194
|
endpoint: '/uploadposts/users/generate-jwt',
|
|
1113
1195
|
method: 'POST',
|
|
@@ -1384,6 +1466,7 @@ class UploadPost {
|
|
|
1384
1466
|
{ name: 'Cancel Scheduled Post', value: 'cancelScheduled', action: 'Cancel scheduled post', description: 'Cancel a scheduled post by its job ID' },
|
|
1385
1467
|
{ name: 'Edit Scheduled Post', value: 'editScheduled', action: 'Edit scheduled post', description: 'Edit schedule details (like date/time) by job ID' },
|
|
1386
1468
|
{ name: 'Get Analytics', value: 'getAnalytics', action: 'Get analytics', description: 'Retrieve aggregated analytics for uploads' },
|
|
1469
|
+
{ name: 'Get Cached Post Analytics', value: 'getCachedPostAnalytics', action: 'Get cached post analytics', description: 'Replay per-post metrics already fetched for a profile instead of querying the platforms again, so it is not subject to the live analytics rate limit (100 requests / 5 minutes). Only contains posts previously fetched through Get Post Analytics; there is no background refresh, so captured_at is the last time that post was read live. Use Get Post Analytics to refresh a post, and this operation for bulk re-reads.' },
|
|
1387
1470
|
{ name: 'Get Job Status', value: 'getJobStatus', action: 'Get job status', description: 'Check the status of a scheduled or queued post using the job_id' },
|
|
1388
1471
|
{ name: 'Get Platform Metrics', value: 'getPlatformMetrics', action: 'Get platform metrics', description: 'List the analytics metrics available for each platform' },
|
|
1389
1472
|
{ name: 'Get Post Analytics', value: 'getPostAnalytics', action: 'Get post analytics', description: 'Retrieve per-post analytics for an upload using its request_id' },
|
|
@@ -2156,6 +2239,69 @@ class UploadPost {
|
|
|
2156
2239
|
description: 'Upload-Post profile that owns the connected account',
|
|
2157
2240
|
displayOptions: { show: { operation: ['getPostAnalyticsByPlatformId'] } },
|
|
2158
2241
|
},
|
|
2242
|
+
{
|
|
2243
|
+
displayName: 'Profile Username',
|
|
2244
|
+
name: 'cachedAnalyticsProfileUsername',
|
|
2245
|
+
type: 'string',
|
|
2246
|
+
required: true,
|
|
2247
|
+
default: '',
|
|
2248
|
+
description: 'Profile username whose cached post metrics you want',
|
|
2249
|
+
displayOptions: { show: { operation: ['getCachedPostAnalytics'] } },
|
|
2250
|
+
},
|
|
2251
|
+
{
|
|
2252
|
+
displayName: 'Platform',
|
|
2253
|
+
name: 'cachedAnalyticsPlatform',
|
|
2254
|
+
type: 'options',
|
|
2255
|
+
options: [
|
|
2256
|
+
{ name: 'All Platforms', value: '' },
|
|
2257
|
+
{ name: 'Facebook', value: 'facebook' },
|
|
2258
|
+
{ name: 'Instagram', value: 'instagram' },
|
|
2259
|
+
{ name: 'LinkedIn', value: 'linkedin' },
|
|
2260
|
+
{ name: 'Pinterest', value: 'pinterest' },
|
|
2261
|
+
{ name: 'Reddit', value: 'reddit' },
|
|
2262
|
+
{ name: 'Threads', value: 'threads' },
|
|
2263
|
+
{ name: 'TikTok', value: 'tiktok' },
|
|
2264
|
+
{ name: 'YouTube', value: 'youtube' },
|
|
2265
|
+
],
|
|
2266
|
+
default: '',
|
|
2267
|
+
description: 'Restrict the result to a single platform. X (Twitter) is not available: the snapshot cache does not store it.',
|
|
2268
|
+
displayOptions: { show: { operation: ['getCachedPostAnalytics'] } },
|
|
2269
|
+
},
|
|
2270
|
+
{
|
|
2271
|
+
displayName: 'Limit',
|
|
2272
|
+
name: 'cachedAnalyticsLimit',
|
|
2273
|
+
type: 'number',
|
|
2274
|
+
typeOptions: { minValue: 1, maxValue: 200 },
|
|
2275
|
+
default: 50,
|
|
2276
|
+
description: 'Max number of results to return',
|
|
2277
|
+
displayOptions: { show: { operation: ['getCachedPostAnalytics'] } },
|
|
2278
|
+
},
|
|
2279
|
+
{
|
|
2280
|
+
displayName: 'Cursor',
|
|
2281
|
+
name: 'cachedAnalyticsCursor',
|
|
2282
|
+
type: 'string',
|
|
2283
|
+
default: '',
|
|
2284
|
+
description: 'Opaque pagination cursor. Pass the next_cursor returned by the previous call to fetch the following page.',
|
|
2285
|
+
displayOptions: { show: { operation: ['getCachedPostAnalytics'] } },
|
|
2286
|
+
},
|
|
2287
|
+
{
|
|
2288
|
+
displayName: 'Since',
|
|
2289
|
+
name: 'cachedAnalyticsSince',
|
|
2290
|
+
type: 'string',
|
|
2291
|
+
default: '',
|
|
2292
|
+
placeholder: 'YYYY-MM-DD',
|
|
2293
|
+
description: 'Start of the snapshot date range. Defaults to 30 days ago.',
|
|
2294
|
+
displayOptions: { show: { operation: ['getCachedPostAnalytics'] } },
|
|
2295
|
+
},
|
|
2296
|
+
{
|
|
2297
|
+
displayName: 'Until',
|
|
2298
|
+
name: 'cachedAnalyticsUntil',
|
|
2299
|
+
type: 'string',
|
|
2300
|
+
default: '',
|
|
2301
|
+
placeholder: 'YYYY-MM-DD',
|
|
2302
|
+
description: 'End of the snapshot date range. Defaults to today.',
|
|
2303
|
+
displayOptions: { show: { operation: ['getCachedPostAnalytics'] } },
|
|
2304
|
+
},
|
|
2159
2305
|
{
|
|
2160
2306
|
displayName: 'Profile Username',
|
|
2161
2307
|
name: 'impressionsProfileUsername',
|
|
@@ -2343,8 +2489,43 @@ class UploadPost {
|
|
|
2343
2489
|
{ name: 'English', value: 'en' },
|
|
2344
2490
|
{ name: 'French', value: 'fr' },
|
|
2345
2491
|
{ name: 'German', value: 'de' },
|
|
2492
|
+
{ name: 'Polish', value: 'pl' },
|
|
2346
2493
|
{ name: 'Portuguese', value: 'pt' },
|
|
2347
2494
|
{ name: 'Spanish', value: 'es' },
|
|
2495
|
+
{ name: 'Turkish', value: 'tr' },
|
|
2496
|
+
],
|
|
2497
|
+
displayOptions: { show: { operation: ['generateJwt'] } },
|
|
2498
|
+
},
|
|
2499
|
+
{
|
|
2500
|
+
displayName: 'UI Labels',
|
|
2501
|
+
name: 'uiLabels',
|
|
2502
|
+
type: 'fixedCollection',
|
|
2503
|
+
typeOptions: { multipleValues: true },
|
|
2504
|
+
placeholder: 'Add UI Label',
|
|
2505
|
+
default: {},
|
|
2506
|
+
description: 'Override individual texts of the connection page, for white-label integrations. Each entry is an i18n dot-path key (for example connect.connectButton) plus the replacement string, and is sent as ui_labels. The API accepts at most 100 entries, keys matching ^[a-zA-Z0-9_.]+$ and values of up to 300 characters, and returns an error otherwise.',
|
|
2507
|
+
options: [
|
|
2508
|
+
{
|
|
2509
|
+
displayName: 'Label',
|
|
2510
|
+
name: 'label',
|
|
2511
|
+
values: [
|
|
2512
|
+
{
|
|
2513
|
+
displayName: 'Key',
|
|
2514
|
+
name: 'key',
|
|
2515
|
+
type: 'string',
|
|
2516
|
+
default: '',
|
|
2517
|
+
placeholder: 'connect.connectButton',
|
|
2518
|
+
description: 'I18n dot-path key of the connection page text to override',
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
displayName: 'Value',
|
|
2522
|
+
name: 'value',
|
|
2523
|
+
type: 'string',
|
|
2524
|
+
default: '',
|
|
2525
|
+
description: 'Replacement text shown on the connection page',
|
|
2526
|
+
},
|
|
2527
|
+
],
|
|
2528
|
+
},
|
|
2348
2529
|
],
|
|
2349
2530
|
displayOptions: { show: { operation: ['generateJwt'] } },
|
|
2350
2531
|
},
|
|
@@ -2693,13 +2874,14 @@ class UploadPost {
|
|
|
2693
2874
|
name: 'tiktokPrivacyLevel',
|
|
2694
2875
|
type: 'options',
|
|
2695
2876
|
options: [
|
|
2696
|
-
{ name: '
|
|
2697
|
-
{ name: 'Mutual Follow Friends', value: 'MUTUAL_FOLLOW_FRIENDS' },
|
|
2877
|
+
{ name: 'Account Default', value: '' },
|
|
2698
2878
|
{ name: 'Follower of Creator', value: 'FOLLOWER_OF_CREATOR' },
|
|
2879
|
+
{ name: 'Mutual Follow Friends', value: 'MUTUAL_FOLLOW_FRIENDS' },
|
|
2880
|
+
{ name: 'Public to Everyone', value: 'PUBLIC_TO_EVERYONE' },
|
|
2699
2881
|
{ name: 'Self Only', value: 'SELF_ONLY' },
|
|
2700
2882
|
],
|
|
2701
|
-
default: '
|
|
2702
|
-
description: 'Privacy setting for TikTok video
|
|
2883
|
+
default: '',
|
|
2884
|
+
description: 'Privacy setting for the TikTok video. TikTok decides per account which levels are available: a private account has no Public to Everyone, and asking for one the account does not have fails with tiktok_privacy_unavailable listing the allowed ones. Account Default sends nothing and lets TikTok apply the account\'s own setting, which is the only value guaranteed to work on every account. Only for Upload Video.',
|
|
2703
2885
|
displayOptions: {
|
|
2704
2886
|
show: {
|
|
2705
2887
|
operation: ['uploadVideo'],
|
|
@@ -2802,6 +2984,140 @@ class UploadPost {
|
|
|
2802
2984
|
}
|
|
2803
2985
|
},
|
|
2804
2986
|
},
|
|
2987
|
+
{
|
|
2988
|
+
displayName: 'TikTok Music ID',
|
|
2989
|
+
name: 'tiktokMusicId',
|
|
2990
|
+
type: 'string',
|
|
2991
|
+
default: '',
|
|
2992
|
+
description: 'Commercial Music Library track ID to add to the post: the ID field returned by the TikTok trending-music or music-search endpoint, not its commercial_music_id. To find a track by song or artist, call GET /api/uploadposts/tiktok/music/search from an HTTP Request node first. Works on video and photo posts alike, but a photo post takes the ID alone: the volume and trim options below are video-only. Needs the music capability on the TikTok connection (see capabilities in the user-profiles response); without it the field is ignored with a warning and the post still publishes. Leave empty to skip.',
|
|
2993
|
+
displayOptions: {
|
|
2994
|
+
show: {
|
|
2995
|
+
operation: ['uploadVideo', 'uploadPhotos'],
|
|
2996
|
+
platform: ['tiktok', '__manual_platform__']
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
},
|
|
3000
|
+
{
|
|
3001
|
+
displayName: 'TikTok Music Volume',
|
|
3002
|
+
name: 'tiktokMusicVolume',
|
|
3003
|
+
type: 'number',
|
|
3004
|
+
default: 50,
|
|
3005
|
+
typeOptions: { minValue: 0, maxValue: 100 },
|
|
3006
|
+
description: 'Volume (0-100) of the Commercial Music Library track. Only sent when a TikTok Music ID is set.',
|
|
3007
|
+
displayOptions: {
|
|
3008
|
+
show: {
|
|
3009
|
+
operation: ['uploadVideo'],
|
|
3010
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3011
|
+
}
|
|
3012
|
+
},
|
|
3013
|
+
},
|
|
3014
|
+
{
|
|
3015
|
+
displayName: 'TikTok Music Start (Ms)',
|
|
3016
|
+
name: 'tiktokMusicStart',
|
|
3017
|
+
type: 'number',
|
|
3018
|
+
default: 0,
|
|
3019
|
+
typeOptions: { minValue: 0 },
|
|
3020
|
+
description: 'Start offset (ms) of the music track. Only sent when a TikTok Music ID is set and this is above 0.',
|
|
3021
|
+
displayOptions: {
|
|
3022
|
+
show: {
|
|
3023
|
+
operation: ['uploadVideo'],
|
|
3024
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3025
|
+
}
|
|
3026
|
+
},
|
|
3027
|
+
},
|
|
3028
|
+
{
|
|
3029
|
+
displayName: 'TikTok Music End (Ms)',
|
|
3030
|
+
name: 'tiktokMusicEnd',
|
|
3031
|
+
type: 'number',
|
|
3032
|
+
default: 0,
|
|
3033
|
+
typeOptions: { minValue: 0 },
|
|
3034
|
+
description: 'End offset (ms) of the music track. Only sent when a TikTok Music ID is set and this is above 0.',
|
|
3035
|
+
displayOptions: {
|
|
3036
|
+
show: {
|
|
3037
|
+
operation: ['uploadVideo'],
|
|
3038
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3039
|
+
}
|
|
3040
|
+
},
|
|
3041
|
+
},
|
|
3042
|
+
{
|
|
3043
|
+
displayName: 'TikTok Original Sound Volume',
|
|
3044
|
+
name: 'tiktokOriginalSoundVolume',
|
|
3045
|
+
type: 'number',
|
|
3046
|
+
default: 50,
|
|
3047
|
+
typeOptions: { minValue: 0, maxValue: 100 },
|
|
3048
|
+
description: 'Volume (0-100) of the original video audio when music is added. Only sent when a TikTok Music ID is set. Keep it above 0 so the original audio is not muted.',
|
|
3049
|
+
displayOptions: {
|
|
3050
|
+
show: {
|
|
3051
|
+
operation: ['uploadVideo'],
|
|
3052
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3053
|
+
}
|
|
3054
|
+
},
|
|
3055
|
+
},
|
|
3056
|
+
{
|
|
3057
|
+
displayName: 'TikTok Location ID',
|
|
3058
|
+
name: 'tiktokLocationId',
|
|
3059
|
+
type: 'string',
|
|
3060
|
+
default: '',
|
|
3061
|
+
description: 'Location ID to tag on the post (video or photos). Needs the location capability on the TikTok connection (see capabilities in the user-profiles response) and a TikTok Location Name — the tag is only sent when both are filled in. Without the capability the field is ignored with a warning and the post still publishes. Leave empty to skip.',
|
|
3062
|
+
displayOptions: {
|
|
3063
|
+
show: {
|
|
3064
|
+
operation: ['uploadVideo', 'uploadPhotos'],
|
|
3065
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3066
|
+
}
|
|
3067
|
+
},
|
|
3068
|
+
},
|
|
3069
|
+
{
|
|
3070
|
+
displayName: 'TikTok Location Name',
|
|
3071
|
+
name: 'tiktokLocationName',
|
|
3072
|
+
type: 'string',
|
|
3073
|
+
default: '',
|
|
3074
|
+
description: 'Location name matching the TikTok Location ID. TikTok requires both together, so the location tag is only sent when this and the ID are both filled in.',
|
|
3075
|
+
displayOptions: {
|
|
3076
|
+
show: {
|
|
3077
|
+
operation: ['uploadVideo', 'uploadPhotos'],
|
|
3078
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3079
|
+
}
|
|
3080
|
+
},
|
|
3081
|
+
},
|
|
3082
|
+
{
|
|
3083
|
+
displayName: 'TikTok Cover Image URL',
|
|
3084
|
+
name: 'tiktokCoverImageUrl',
|
|
3085
|
+
type: 'string',
|
|
3086
|
+
default: '',
|
|
3087
|
+
description: 'Custom cover image URL for the video. Needs the cover_image capability on the TikTok connection (see capabilities in the user-profiles response); without it the field is ignored with a warning and the post still publishes. Takes priority over TikTok Cover Timestamp.',
|
|
3088
|
+
displayOptions: {
|
|
3089
|
+
show: {
|
|
3090
|
+
operation: ['uploadVideo'],
|
|
3091
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3092
|
+
}
|
|
3093
|
+
},
|
|
3094
|
+
},
|
|
3095
|
+
{
|
|
3096
|
+
displayName: 'TikTok Is AI Generated',
|
|
3097
|
+
name: 'tiktokIsAiGenerated',
|
|
3098
|
+
type: 'boolean',
|
|
3099
|
+
default: false,
|
|
3100
|
+
description: 'Whether to disclose the post as AI-generated on TikTok. Works on video and photo posts. Only sent when enabled.',
|
|
3101
|
+
displayOptions: {
|
|
3102
|
+
show: {
|
|
3103
|
+
operation: ['uploadVideo', 'uploadPhotos'],
|
|
3104
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3105
|
+
}
|
|
3106
|
+
},
|
|
3107
|
+
},
|
|
3108
|
+
{
|
|
3109
|
+
displayName: 'TikTok Upload to Draft',
|
|
3110
|
+
name: 'tiktokUploadToDraft',
|
|
3111
|
+
type: 'boolean',
|
|
3112
|
+
default: false,
|
|
3113
|
+
description: 'Whether to send the video to TikTok drafts instead of publishing it. Needs the draft capability on the TikTok connection (see capabilities in the user-profiles response); without it the field is ignored with a warning and the post still publishes. When enabled TikTok ignores the rest of the post settings.',
|
|
3114
|
+
displayOptions: {
|
|
3115
|
+
show: {
|
|
3116
|
+
operation: ['uploadVideo'],
|
|
3117
|
+
platform: ['tiktok', '__manual_platform__']
|
|
3118
|
+
}
|
|
3119
|
+
},
|
|
3120
|
+
},
|
|
2805
3121
|
{
|
|
2806
3122
|
displayName: 'Instagram Media Type',
|
|
2807
3123
|
name: 'instagramMediaType',
|
|
@@ -2995,6 +3311,43 @@ class UploadPost {
|
|
|
2995
3311
|
description: 'Format of the attached media',
|
|
2996
3312
|
displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['google_business', '__manual_platform__'] } },
|
|
2997
3313
|
},
|
|
3314
|
+
{
|
|
3315
|
+
displayName: 'Google Business Publish As',
|
|
3316
|
+
name: 'gbpPostType',
|
|
3317
|
+
type: 'options',
|
|
3318
|
+
options: [
|
|
3319
|
+
{ name: 'Gallery', value: 'GALLERY' },
|
|
3320
|
+
{ name: 'Local Post (Default)', value: '' },
|
|
3321
|
+
{ name: 'Media', value: 'MEDIA' },
|
|
3322
|
+
{ name: 'Photo', value: 'PHOTO' },
|
|
3323
|
+
],
|
|
3324
|
+
default: '',
|
|
3325
|
+
description: 'Where the upload lands on the Google Business Profile. Local Post keeps the default behaviour and creates a post on the timeline. Media, Photo and Gallery all publish the image to the location Media/Gallery tab instead, without creating a Local Post.',
|
|
3326
|
+
displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['google_business', '__manual_platform__'] } },
|
|
3327
|
+
},
|
|
3328
|
+
{
|
|
3329
|
+
displayName: 'Google Business Media Category',
|
|
3330
|
+
name: 'gbpMediaCategory',
|
|
3331
|
+
type: 'options',
|
|
3332
|
+
options: [
|
|
3333
|
+
{ name: 'Additional', value: 'ADDITIONAL' },
|
|
3334
|
+
{ name: 'At Work', value: 'AT_WORK' },
|
|
3335
|
+
{ name: 'Common Area', value: 'COMMON_AREA' },
|
|
3336
|
+
{ name: 'Cover', value: 'COVER' },
|
|
3337
|
+
{ name: 'Exterior', value: 'EXTERIOR' },
|
|
3338
|
+
{ name: 'Food and Drink', value: 'FOOD_AND_DRINK' },
|
|
3339
|
+
{ name: 'Interior', value: 'INTERIOR' },
|
|
3340
|
+
{ name: 'Logo', value: 'LOGO' },
|
|
3341
|
+
{ name: 'Menu', value: 'MENU' },
|
|
3342
|
+
{ name: 'Product', value: 'PRODUCT' },
|
|
3343
|
+
{ name: 'Profile', value: 'PROFILE' },
|
|
3344
|
+
{ name: 'Rooms', value: 'ROOMS' },
|
|
3345
|
+
{ name: 'Teams', value: 'TEAMS' },
|
|
3346
|
+
],
|
|
3347
|
+
default: 'ADDITIONAL',
|
|
3348
|
+
description: 'Category the photo is filed under in the Media/Gallery tab. Only used when Publish As is Media, Photo or Gallery.',
|
|
3349
|
+
displayOptions: { show: { operation: ['uploadPhotos', 'uploadVideo', 'uploadText'], platform: ['google_business', '__manual_platform__'], gbpPostType: ['GALLERY', 'MEDIA', 'PHOTO'] } },
|
|
3350
|
+
},
|
|
2998
3351
|
{
|
|
2999
3352
|
displayName: 'Google Business Call to Action',
|
|
3000
3353
|
name: 'gbpCtaType',
|