@bernierllc/social-media-tiktok
v1.2.0
Published
TikTok Content Posting API integration service with OAuth 2.0 authentication, direct-post video publishing (PULL_FROM_URL), and publish status polling
Readme
@bernierllc/social-media-tiktok
TikTok Content Posting API integration service with OAuth 2.0 authentication, direct-post video publishing (PULL_FROM_URL), and publish status polling.
⚠️ Unaudited apps: private/draft content only
Until your TikTok developer app passes TikTok's audit review, direct-post content can only be published as private/draft — you must use privacyLevel: 'SELF_ONLY'. Public privacy levels (PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR) are rejected by TikTok for unaudited apps. See TikTok's Content Posting API guide for the audit process.
Features
- OAuth 2.0 Authentication: Authorization URL builder, code→token exchange, refresh token flow
- Direct Post Publishing:
PULL_FROM_URLvideo init against the Content Posting API - Publish Status Polling: Poll the documented fetch-status endpoint for
PROCESSING_DOWNLOAD→PUBLISH_COMPLETE/FAILED - Single-account: one
TiktokServiceinstance holds one account's credentials — create multiple instances for multiple accounts - NeverHub: Optional service-discovery registration with graceful degradation
- TypeScript Support: Full type definitions included
Installation
npm install @bernierllc/social-media-tiktokQuick Start
import { TiktokService } from '@bernierllc/social-media-tiktok';
const tiktok = new TiktokService({
clientKey: process.env.TIKTOK_CLIENT_KEY!,
clientSecret: process.env.TIKTOK_CLIENT_SECRET!,
redirectUri: 'https://my-app.com/callback',
});Authentication Flow
// 1. Build the authorization URL and redirect the user to it
const state = crypto.randomUUID();
const authUrl = tiktok.getAuthorizationUrl(['user.info.basic', 'video.publish'], state);
// 2. After TikTok redirects back with ?code=...&state=...,
// verify `state` matches what you generated, then exchange the code
const credentials = await tiktok.authenticate(code);
console.log('Authenticated:', credentials.openId);
// 3. Refresh when the access token expires (documented as 24h validity;
// refresh token is valid 365d)
const refreshed = await tiktok.refreshAccessToken();Publishing a Video (Direct Post, PULL_FROM_URL)
const post = await tiktok.post({
postInfo: {
privacyLevel: 'SELF_ONLY', // required until your app passes audit
title: 'Hello TikTok!',
disableComment: false,
},
sourceInfo: {
source: 'PULL_FROM_URL',
videoUrl: 'https://cdn.example.com/my-video.mp4', // must be publicly reachable
},
});
if (post.success) {
console.log('Publish ID:', post.publishId);
}Polling Publish Status
const status = await tiktok.getPublishStatus(post.publishId!);
switch (status.status) {
case 'PUBLISH_COMPLETE':
console.log('Live:', status.publiclyAvailablePostId);
break;
case 'FAILED':
console.error('Failed:', status.failReason);
break;
default:
// PROCESSING_DOWNLOAD, PROCESSING_UPLOAD, SEND_TO_USER_INBOX — poll again later
break;
}NeverHub Service Discovery
initialize() registers the service with NeverHub. It is entirely optional —
every method below works without calling it — and it is safe to call when
NeverHub is not running: registration silently no-ops in degraded mode.
await tiktok.initialize();API Reference
TiktokService
| Method | Description |
|---|---|
| getAuthorizationUrl(scopes, state) | Builds the https://www.tiktok.com/v2/auth/authorize/ URL |
| authenticate(code) | Exchanges an authorization code for credentials (stores them on the instance) |
| refreshAccessToken(refreshToken?) | Refreshes the access token |
| post(request) | Initiates a direct-post video publish (PULL_FROM_URL) |
| getPublishStatus(publishId) | Polls publish status |
| isAuthenticated() | Whether credentials are stored |
| getCredentials() | Returns stored credentials, or null |
Documented scopes
user.info.basic, video.list, video.upload, video.publish — request only the scopes your feature needs.
Documented publish statuses
PROCESSING_UPLOAD, PROCESSING_DOWNLOAD, SEND_TO_USER_INBOX, PUBLISH_COMPLETE, FAILED
Error Handling
All unexpected/network failures throw SocialMediaTiktokError (extends Error, uses Error.cause). Expected API-level failures (not authenticated, TikTok error envelope) return a { success: false, error, errorCode? } result instead of throwing, matching sibling @bernierllc/social-media-* packages.
import { SocialMediaTiktokError } from '@bernierllc/social-media-tiktok';
try {
await tiktok.authenticate(code);
} catch (error) {
if (error instanceof SocialMediaTiktokError) {
console.error(error.code, error.message, error.cause);
}
}References
- TikTok Content Posting API — Get Started
- Direct Post reference
- Get Post Status reference
- OAuth / User Access Token Management
License
SEE LICENSE IN LICENSE
