upload-post
Version:
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)
416 lines (320 loc) • 13.4 kB
Markdown
Official Node.js client for the [Upload-Post API](https://www.upload-post.com) - Cross-platform social media upload.
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.
```bash
npm install upload-post
```
```javascript
import { UploadPost } from 'upload-post';
const client = new UploadPost('YOUR_API_KEY');
// Upload a video to multiple platforms
const response = await client.upload('./video.mp4', {
title: 'Check out this awesome video! 🎬',
user: 'my-profile',
platforms: ['tiktok', 'instagram', 'youtube']
});
console.log(response);
```
- ✅ **Video Upload** - TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Bluesky, X, Discord, Telegram
- ✅ **Photo Upload** - TikTok, Instagram, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, X, Discord, Telegram
- ✅ **Text Posts** - X, LinkedIn, Facebook, Threads, Reddit, Bluesky, Discord, Telegram
- ✅ **Document Upload** - LinkedIn (PDF, PPT, PPTX, DOC, DOCX)
- ✅ **Scheduling** - Schedule posts for later
- ✅ **Posting Queue** - Add posts to your configured queue
- ✅ **First Comments** - Auto-post first comment after publishing
- ✅ **Analytics** - Get engagement metrics
- ✅ **Full TypeScript Support**
```javascript
const response = await client.upload('./video.mp4', {
title: 'My awesome video',
user: 'my-profile',
platforms: ['tiktok', 'instagram', 'youtube'],
// Optional: Schedule for later
scheduledDate: '2024-12-25T10:00:00Z',
timezone: 'Europe/Madrid',
// Optional: Add first comment
firstComment: 'Thanks for watching! 🙏',
// Optional: Platform-specific settings
tiktokPrivacyLevel: 'PUBLIC_TO_EVERYONE',
instagramMediaType: 'REELS',
youtubePrivacyStatus: 'public',
youtubeTags: ['tutorial', 'coding'],
});
```
```javascript
// Upload single or multiple photos
const response = await client.uploadPhotos(
['./photo1.jpg', './photo2.jpg', 'https://example.com/photo3.jpg'],
{
title: 'Check out these photos! 📸',
user: 'my-profile',
platforms: ['instagram', 'facebook', 'x'],
// Optional: Add to queue instead of posting immediately
addToQueue: true,
// Platform-specific
instagramMediaType: 'IMAGE', // or 'STORIES'
facebookPageId: 'your-page-id',
}
);
```
```javascript
const response = await client.uploadText({
title: 'Just shipped a new feature! 🚀 Check it out at example.com',
user: 'my-profile',
platforms: ['x', 'linkedin', 'threads'],
// Optional: Create a poll on X
xPollOptions: ['Option A', 'Option B', 'Option C'],
xPollDuration: 1440, // 24 hours in minutes
// Optional: Post to a LinkedIn company page
targetLinkedinPageId: 'company-page-id',
});
```
```javascript
const response = await client.uploadDocument('./presentation.pdf', {
title: 'Q4 2024 Report',
user: 'my-profile',
description: 'Check out our latest quarterly results!',
linkedinVisibility: 'PUBLIC',
targetLinkedinPageId: 'company-page-id', // Optional: post to company page
});
```
For async uploads, check the status using the request_id:
```javascript
const status = await client.getStatus('request_id_from_upload');
console.log(status);
```
For scheduled or queued posts, check the status using the job_id:
```javascript
const status = await client.getJobStatus('job_id_from_scheduled_post');
console.log(status);
```
```javascript
const history = await client.getHistory({ page: 1, limit: 20 });
console.log(history.uploads);
```
```javascript
// List all scheduled posts
const scheduled = await client.listScheduled();
// Edit a scheduled post
await client.editScheduled('job-id', {
scheduledDate: '2024-12-26T15:00:00Z',
timezone: 'America/New_York',
});
// Cancel a scheduled post
await client.cancelScheduled('job-id');
```
```javascript
// List all profiles
const users = await client.listUsers();
// Create a new profile
await client.createUser('new-profile');
// Delete a profile
await client.deleteUser('old-profile');
// Generate JWT for platform integration (white-label)
const jwt = await client.generateJwt('my-profile', {
redirectUrl: 'https://yourapp.com/callback',
platforms: ['tiktok', 'instagram'],
// Optional: force the connection page language for this profile.
// Supported: 'en' | 'es' | 'de' | 'fr' | 'pt'. When omitted, the page
// auto-detects the visitor's browser language and falls back to English.
language: 'es',
});
```
```javascript
const analytics = await client.getAnalytics('my-profile', {
platforms: ['instagram', 'tiktok'],
});
console.log(analytics);
```
Retrieve recent posts from a connected social account. Supported platforms:
`instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
`pinterest`, `bluesky`, `reddit`.
```javascript
const { media } = await client.getMedia('linkedin', 'my-profile');
// Force the personal LinkedIn profile of an account connected as an org admin:
await client.getMedia('linkedin', 'my-profile', { pageUrn: 'me' });
// Target a specific LinkedIn organization page:
await client.getMedia('linkedin', 'my-profile', { pageUrn: '12345' });
```
```javascript
// Get Facebook pages for a profile
const fbPages = await client.getFacebookPages('my-profile');
// Get LinkedIn pages for a profile
const liPages = await client.getLinkedinPages('my-profile');
// Get Pinterest boards for a profile
const boards = await client.getPinterestBoards('my-profile');
```
- `tiktokPrivacyLevel` - PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY
- `tiktokDisableDuet` - Disable duet
- `tiktokDisableComment` - Disable comments
- `tiktokDisableStitch` - Disable stitch
- `tiktokCoverTimestamp` - Timestamp in ms for cover
- `tiktokIsAigc` - AI-generated content flag
- `tiktokPostMode` - DIRECT_POST or MEDIA_UPLOAD
- `brandContentToggle` - Branded content toggle
- `brandOrganicToggle` - Brand organic toggle
- `tiktokAutoAddMusic` - Auto add music
- `tiktokPhotoCoverIndex` - Index of photo for cover (0-based)
- `tiktokDisableComment` - Disable comments
### Instagram
- `instagramMediaType` - REELS, STORIES, IMAGE
- `instagramShareToFeed` - Share to feed (for Reels/Stories)
- `instagramCollaborators` - Comma-separated collaborator usernames
- `instagramCoverUrl` - Custom cover URL
- `instagramAudioName` - Audio track name
- `instagramUserTags` - Comma-separated user tags
- `instagramLocationId` - Location ID
- `instagramThumbOffset` - Thumbnail offset
### YouTube
- `youtubeTags` - Array or comma-separated tags
- `youtubeCategoryId` - Category ID (default: "22" People & Blogs)
- `youtubePrivacyStatus` - public, unlisted, private
- `youtubeEmbeddable` - Allow embedding
- `youtubeLicense` - youtube, creativeCommon
- `youtubePublicStatsViewable` - Show public stats
- `youtubeThumbnailUrl` - Custom thumbnail URL
- `youtubeSelfDeclaredMadeForKids` - Made for kids (COPPA)
- `youtubeContainsSyntheticMedia` - AI/synthetic content flag
- `youtubeDefaultLanguage` - Title/description language (BCP-47)
- `youtubeDefaultAudioLanguage` - Audio language (BCP-47)
- `youtubeAllowedCountries` / `youtubeBlockedCountries` - Country restrictions
- `youtubeHasPaidProductPlacement` - Paid placement flag
- `youtubeRecordingDate` - Recording date (ISO 8601)
### LinkedIn
- `linkedinVisibility` - PUBLIC, CONNECTIONS, LOGGED_IN, CONTAINER
- `targetLinkedinPageId` - Page ID for organization posts
### Facebook
- `facebookPageId` - Facebook Page ID (required)
- `facebookVideoState` - PUBLISHED, DRAFT
- `facebookMediaType` - REELS, STORIES, VIDEO (VIDEO for normal page videos with no 9:16 restriction)
- `thumbnailUrl` - URL for custom video thumbnail (only when facebookMediaType is VIDEO)
- `facebookLinkUrl` - URL for text posts
### Pinterest
- `pinterestBoardId` - Board ID
- `pinterestLink` - Destination link
- `pinterestAltText` - Alt text for photos
- `pinterestCoverImageUrl` - Cover image URL (video)
- `pinterestCoverImageKeyFrameTime` - Key frame time in ms
### X (Twitter)
- `xReplySettings` - everyone, following, mentionedUsers, subscribers, verified
- `xNullcast` - Promoted-only post
- `xTaggedUserIds` - User IDs to tag
- `xPlaceId` / `xGeoPlaceId` - Location place ID
- `xQuoteTweetId` - Tweet ID to quote
- `xPollOptions` - Poll options (2-4)
- `xPollDuration` - Poll duration in minutes (5-10080)
- `xForSuperFollowersOnly` - Exclusive for super followers
- `xCommunityId` - Community ID
- `xShareWithFollowers` - Share community post with followers
- `xCardUri` - Card URI for Twitter Cards
- `xLongTextAsPost` - Post long text as single post
- `xThreadImageLayout` - Comma-separated image layout for thread (e.g. "4,4" or "2,3,1")
### Threads
- `threadsLongTextAsPost` - Post long text as single post (vs thread)
- `threadsThreadMediaLayout` - Comma-separated list of how many media items to include in each Threads post. Each value must be 1-10, and the total must equal the number of files. Example: '5,5' splits 10 items into 2 posts with 5 each. If omitted and more than 10 items are provided, auto-chunks into groups of 10.
- `threadsTopicTag` - Topic tag for the Threads post (1-50 characters, no periods or ampersands). One tag per post. Helps increase reach.
### Reddit
- `redditSubreddit` - Subreddit name (without r/)
- `redditFlairId` - Flair template ID
## Common Options
These options work across all upload methods:
| Option | Description |
|--------|-------------|
| `title` | Post title/caption (required) |
| `user` | Profile name (required) |
| `platforms` | Target platforms array (required) |
| `firstComment` | First comment to post |
| `altText` | Alt text for accessibility |
| `scheduledDate` | ISO date for scheduling |
| `timezone` | Timezone for scheduled date |
| `addToQueue` | Add to posting queue |
| `maxPostsPerSlot` | Max posts per queue slot (overrides profile setting) |
| `asyncUpload` | Process asynchronously (default: true) |
| `idempotencyKey` | Collapses duplicate uploads within 24h. Reuse the same value when retrying. Alias: `requestId` |
## Google Business Profile
Pass the target location on the upload itself. There is no separate "select a location" call — the API resolves the location per post.
```javascript
const { locations } = await client.getGoogleBusinessLocations('myprofile');
await client.upload('video.mp4', {
user: 'myprofile',
platforms: ['google_business'],
title: 'Now open on Sundays',
gbpLocationId: locations[0].name, // "accounts/123/locations/456"
});
```
`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:
```javascript
await client.uploadText({
user: 'myprofile',
platforms: ['google_business'],
title: 'Summer sale',
gbpLocationId: locations[0].name,
gbpTopicType: 'OFFER',
gbpOfferCoupon: 'SUMMER25',
gbpOfferRedeemUrl: 'https://example.com/redeem',
gbpOfferTerms: 'One per customer',
});
```
Also available: `gbpTopicType: 'EVENT'` with `gbpEventTitle` / `gbpEventStartDate` / `gbpEventStartTime` / `gbpEventEndDate` / `gbpEventEndTime`, a call-to-action via `gbpCtaType` + `gbpCtaUrl`, and `gbpMediaUrl` / `gbpMediaFormat`.
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.
Pass the same `idempotencyKey` on every attempt and the API returns the original job instead of creating a new one:
```javascript
import { randomUUID } from 'crypto';
const idempotencyKey = randomUUID(); // generate ONCE, outside the retry loop
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await client.upload('video.mp4', { user, platforms: ['tiktok'], title, idempotencyKey });
} catch (err) {
if (attempt === 2) throw err;
}
}
```
Generating the key inside the loop defeats the mechanism: each attempt would look like a new upload.
Full TypeScript support with comprehensive type definitions:
```typescript
import { UploadPost, UploadVideoOptions, UploadResponse } from 'upload-post';
const client = new UploadPost('YOUR_API_KEY');
const options: UploadVideoOptions = {
title: 'My video',
user: 'my-profile',
platforms: ['tiktok', 'instagram'],
tiktokPrivacyLevel: 'PUBLIC_TO_EVERYONE',
};
const response: UploadResponse = await client.upload('./video.mp4', options);
```
```javascript
try {
const response = await client.upload('./video.mp4', options);
console.log('Upload successful:', response);
} catch (error) {
console.error('Upload failed:', error.message);
}
```
- [Upload-Post Website](https://www.upload-post.com)
- [API Documentation](https://docs.upload-post.com)
- [Dashboard](https://app.upload-post.com)
MIT
<!-- deployed 2026-03-16 17:49 UTC -->