Skip to main content

Social Platform APIs

UniPulse integrates with three social platforms for publishing, analytics, and conversation management. All social API interactions go through the backend -- the frontend never calls platform APIs directly.


Platform Overview​

PlatformAPIAuthPublishingMetricsConversations
FacebookMeta Graph API v19+OAuth 2.0 (Facebook Login)YesYesYes
InstagramMeta Graph API v19+OAuth 2.0 (via Facebook)YesYesYes
TikTokContent Posting API + Display API (v2)OAuth 2.0 (Login Kit)Yes (video)Yes (public videos)No

Facebook & Instagram (Meta Graph API)​

Authentication​

StepEndpointScopes
OAuth initiationGET /api/v1/auth/oauth/facebookpages_manage_posts, pages_read_engagement, pages_manage_metadata, instagram_basic, instagram_content_publish, instagram_manage_comments, instagram_manage_insights
Token exchangeFacebook OAuth callbackAccess token + page tokens
Token refreshAutomatic via token-refresh queueLong-lived tokens (60 days)

Publishing​

PlatformAPI CallContent Types
Facebook PagePOST /{page-id}/feedText, images, videos, links
InstagramPOST /{ig-user-id}/media + POST /{ig-user-id}/media_publishImages, carousels, reels

Metrics Sync​

MetricAPISync Queue
Post reach, impressionsGET /{post-id}/insightsanalytics-sync
Post engagement (likes, comments, shares)GET /{post-id}?fields=likes,comments,sharesanalytics-sync
Page follower countGET /{page-id}/insightsanalytics-sync

Conversations​

FeatureAPIQueue
Read commentsGET /{post-id}/commentsice-process
Reply to commentsPOST /{comment-id}/repliesvia sendAgentReply()
Read DMsMessenger Platform APIice-process
Webhooks (real-time)Facebook Webhooks (comment, message events)webhook-process

TikTok (Content Posting API)​

Implemented in apps/api/src/platforms/tiktok.platform.ts.

TikTok developer app setup​

SettingValue
ProductsLogin Kit, Content Posting API (Direct Post), Display API
Scopesuser.info.basic, video.list, video.publish, video.upload
Redirect URIhttps://app.unipulse.tech/api/v1/auth/oauth/tiktok/callback (HTTPS only, must match byte for byte)
Testing before auditSandbox mode, with the tester's TikTok account added as a target user
warning

TikTok rejects the authorize request if it asks for a scope the app has not been granted, so all four scopes must be enabled. Redirect URIs must be HTTPS, so connecting cannot be tested against localhost.

Credentials come from the workspace's encrypted PlatformCredential row (Settings → platform credentials) and fall back to TIKTOK_CLIENT_KEY / TIKTOK_CLIENT_SECRET / TIKTOK_CALLBACK_URL.

Authentication​

StepEndpointNotes
OAuth initiationPOST /api/v1/auth/oauth/connect (platform: tiktok)Builds the Login Kit authorize URL
Token exchangeGET /api/v1/auth/oauth/tiktok/callback (public)POST /v2/oauth/token/
Account infoGET /v2/user/info/?fields=open_id,union_id,avatar_url,display_namefields is required
Token refreshtoken-refresh queueAccess token lasts 24 h, refresh token 365 days
info

Every TikTok v2 response carries error: { code, message, log_id }, and code is "ok" on success. Check errors with tiktokApiError(), never with a bare data.error?.code.

Publishing​

Direct Post with source: FILE_UPLOAD. The worker downloads the video from its public URL and uploads it to TikTok in chunks: one chunk for files up to 10 MB, otherwise 10 MB chunks with the last one taking the remainder. Videos can be up to 4 GB. PULL_FROM_URL is not used because it needs the media host's domain verified in the TikTok portal, which is impossible for S3 or Cloudinary URLs.

RuleWhy
Posts go out as SELF_ONLYUnaudited apps can only post privately
After the last chunk returns 201, only a TikTok FAILED status counts as failureAny other failure would make the publish worker retry and post the video twice
FAILED reasons TikTok marks "do not retry" return permanent: trueThe worker fails immediately instead of retrying
The video ID is read from the raw response bodypublicaly_available_post_id is a 19-digit int64 that JSON.parse would round

TikTok only returns a video ID for public posts that have passed moderation. Private posts keep their publish_id permanently.

Metrics Sync​

StepAPI
Resolve a stored publish_idPOST /v2/post/publish/status/fetch/
Video likes, comments, shares, viewsPOST /v2/video/query/?fields=... (video.list scope)
Post syncPOST /v2/video/list/?fields=... (public videos only)

When getPostInsights resolves a publish_id it returns resolvedPlatformPostId / resolvedPlatformPostUrl, and analytics-sync writes them onto PostPublication. While no video ID exists it returns unavailable: true, and no PostMetric snapshot is written, so charts never show fake zeros. TikTok has no download count or saves metric, so both are recorded as 0.

Conversations​

Not supported. Login Kit tokens have no comment or DM API: comment management and business messaging belong to the separate TikTok for Business API. getComments returns [], and replyToComment / sendDirectMessage return success: false (TIKTOK_DM_UNSUPPORTED) without calling TikTok.


Token Management​

Social platform tokens are stored encrypted in the SocialAccount model:

FieldStorage
accessTokenAES-256 encrypted (using ENCRYPTION_KEY)
refreshTokenAES-256 encrypted
tokenExpiresAtPlaintext DateTime

Automatic Token Refresh​

The token-refresh queue proactively refreshes tokens before they expire:


Rate Limiting​

Each platform enforces API rate limits. UniPulse implements per-platform rate limiting to stay within bounds:

PlatformRate LimitStrategy
Facebook/Instagram200 calls per hour per userQueue-based throttling
TikTokVaries by endpointExponential backoff on 429

The publish queue processes one platform at a time and implements backoff when rate limits are hit.


Environment Variables​

VariablePlatformRequired For
FACEBOOK_APP_IDFacebook/InstagramOAuth initiation
FACEBOOK_APP_SECRETFacebook/InstagramToken exchange
INSTAGRAM_CALLBACK_URLInstagramOAuth callback
TIKTOK_CLIENT_KEYTikTokOAuth initiation
TIKTOK_CLIENT_SECRETTikTokToken exchange
TIKTOK_CALLBACK_URLTikTokOAuth callback

Cross-Reference