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
| Platform | API | Auth | Publishing | Metrics | Conversations |
|---|---|---|---|---|---|
| Meta Graph API v19+ | OAuth 2.0 (Facebook Login) | Yes | Yes | Yes | |
| Meta Graph API v19+ | OAuth 2.0 (via Facebook) | Yes | Yes | Yes | |
| TikTok | Content Posting API + Display API (v2) | OAuth 2.0 (Login Kit) | Yes (video) | Yes (public videos) | No |
Facebook & Instagram (Meta Graph API)
Authentication
| Step | Endpoint | Scopes |
|---|---|---|
| OAuth initiation | GET /api/v1/auth/oauth/facebook | pages_manage_posts, pages_read_engagement, pages_manage_metadata, instagram_basic, instagram_content_publish, instagram_manage_comments, instagram_manage_insights |
| Token exchange | Facebook OAuth callback | Access token + page tokens |
| Token refresh | Automatic via token-refresh queue | Long-lived tokens (60 days) |
Publishing
| Platform | API Call | Content Types |
|---|---|---|
| Facebook Page | POST /{page-id}/feed | Text, images, videos, links |
POST /{ig-user-id}/media + POST /{ig-user-id}/media_publish | Images, carousels, reels |
Metrics Sync
| Metric | API | Sync Queue |
|---|---|---|
| Post reach, impressions | GET /{post-id}/insights | analytics-sync |
| Post engagement (likes, comments, shares) | GET /{post-id}?fields=likes,comments,shares | analytics-sync |
| Page follower count | GET /{page-id}/insights | analytics-sync |
Conversations
| Feature | API | Queue |
|---|---|---|
| Read comments | GET /{post-id}/comments | ice-process |
| Reply to comments | POST /{comment-id}/replies | via sendAgentReply() |
| Read DMs | Messenger Platform API | ice-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
| Setting | Value |
|---|---|
| Products | Login Kit, Content Posting API (Direct Post), Display API |
| Scopes | user.info.basic, video.list, video.publish, video.upload |
| Redirect URI | https://app.unipulse.tech/api/v1/auth/oauth/tiktok/callback (HTTPS only, must match byte for byte) |
| Testing before audit | Sandbox mode, with the tester's TikTok account added as a target user |
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
| Step | Endpoint | Notes |
|---|---|---|
| OAuth initiation | POST /api/v1/auth/oauth/connect (platform: tiktok) | Builds the Login Kit authorize URL |
| Token exchange | GET /api/v1/auth/oauth/tiktok/callback (public) | POST /v2/oauth/token/ |
| Account info | GET /v2/user/info/?fields=open_id,union_id,avatar_url,display_name | fields is required |
| Token refresh | token-refresh queue | Access token lasts 24 h, refresh token 365 days |
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.
| Rule | Why |
|---|---|
Posts go out as SELF_ONLY | Unaudited apps can only post privately |
After the last chunk returns 201, only a TikTok FAILED status counts as failure | Any other failure would make the publish worker retry and post the video twice |
FAILED reasons TikTok marks "do not retry" return permanent: true | The worker fails immediately instead of retrying |
| The video ID is read from the raw response body | publicaly_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
| Step | API |
|---|---|
Resolve a stored publish_id | POST /v2/post/publish/status/fetch/ |
| Video likes, comments, shares, views | POST /v2/video/query/?fields=... (video.list scope) |
| Post sync | POST /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:
| Field | Storage |
|---|---|
accessToken | AES-256 encrypted (using ENCRYPTION_KEY) |
refreshToken | AES-256 encrypted |
tokenExpiresAt | Plaintext 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:
| Platform | Rate Limit | Strategy |
|---|---|---|
| Facebook/Instagram | 200 calls per hour per user | Queue-based throttling |
| TikTok | Varies by endpoint | Exponential backoff on 429 |
The publish queue processes one platform at a time and implements backoff when rate limits are hit.
Environment Variables
| Variable | Platform | Required For |
|---|---|---|
FACEBOOK_APP_ID | Facebook/Instagram | OAuth initiation |
FACEBOOK_APP_SECRET | Facebook/Instagram | Token exchange |
INSTAGRAM_CALLBACK_URL | OAuth callback | |
TIKTOK_CLIENT_KEY | TikTok | OAuth initiation |
TIKTOK_CLIENT_SECRET | TikTok | Token exchange |
TIKTOK_CALLBACK_URL | TikTok | OAuth callback |
- Auth Flow -- social platform OAuth flows
- Queue System -- publish, analytics-sync, token-refresh queues
- Conversation Engine -- ICE processing of social messages
- Environment Variables -- all env vars