TikTok

TikTok is supported in Outstand through the Bring Your Own Key (BYOK) model. This allows you to use your own TikTok API credentials to connect your TikTok accounts and post content through Outstand's unified social media API.

On the TikTok dev portal register a new app. New apps have sandbox and production environments. You can use the sandbox environment to test your integration before going live.

Before you begin, ensure you have:

  • A TikTok developer account
  • A website or landing page for your application
  • Understanding of OAuth 2.0 flows
  • Access to your website's server/backend to set up callback routing (if using proxy solution)

Step 1: Create a TikTok Developer App

  1. Go to the TikTok Developer Portal
  2. Sign in or create a developer account
  3. Navigate to My Apps and click Create App
  4. Fill in the required information:
    • App Name: Your application name (e.g., "My Video Scheduler" or "Outstand Video Scheduler")
    • App Category: Select the appropriate category
    • Website URL: Your application's website URL (must be HTTPS)
    • Terms of Service URL: Your terms of service page (must be HTTPS)
    • Privacy Policy URL: Your privacy policy page (must be HTTPS)

Important: TikTok requires brand consistency. Your app name, website URL, and redirect URI should all reference the same brand. See the Branding Requirements section below for details.

Step 2: Configure OAuth Settings

Understanding Redirect URIs

TikTok requires that your redirect URI matches your app's branding. Since Outstand uses a fixed callback URL (https://www.outstand.so/app/api/socials/tiktok/callback), you have two options:

Set up a proxy callback on your own domain that forwards requests to Outstand. This ensures TikTok sees your domain in the redirect URI, maintaining brand consistency.

Steps:

  1. In your TikTok app, add your redirect URI
  2. Set up a proxy endpoint on your server that forwards to Outstand's callback
  3. See Proxy Callback Implementation below for code examples

Option B: Use Outstand's Callback Directly

If brand consistency isn't critical for your use case:

  1. In your TikTok app, add the redirect URI: https://www.outstand.so/app/api/socials/tiktok/callback
  2. Ensure your app name and website URL mention Outstand or use generic branding

Required Scopes

Outstand requests the following scopes. You must enable all of them in your TikTok app:

Default Scopes:

  • user.info.basic - Access profile info (avatar and display name) - REQUIRED
  • user.info.profile - Read additional profile info (bio, profile link, verification status) - REQUIRED
  • video.publish - Post content to TikTok (DIRECT_POST mode) - REQUIRED
  • user.info.stats - Read profile engagement statistics (used for account insights)
  • video.upload - Upload draft content to TikTok for further editing (INBOX mode)
  • video.list - Read public videos on TikTok (for post metrics)

Note: While some scopes are technically optional, Outstand currently requests all 6 scopes. You must enable all of them in your TikTok app configuration for the OAuth flow to work.

Step 3: Set Up Sandbox Testing

Before submitting for approval, test your integration using TikTok's sandbox environment:

  1. In your TikTok app, navigate to Sandbox
  2. Add a test user (your TikTok account)
  3. Test the OAuth flow and posting functionality
  4. Ensure all scopes work as expected

Step 4: Submit for Review

TikTok requires app review before you can use production APIs. To pass review:

Common Rejection Reasons

TikTok may reject your app if:

  1. Brand Inconsistency: App name, website, and redirect URI don't match

    • Solution: Use the proxy callback approach (see below)
  2. Missing Scope Demonstration: Demo video doesn't show all enabled scopes

    • Solution: Update demo video to show each scope being used
  3. Invalid Website: Website URL doesn't exist or isn't accessible

    • Solution: Ensure your website is live and accessible via HTTPS
  4. Incomplete Demo Video: Video doesn't show the complete user flow

    • Solution: Record a comprehensive demo showing OAuth → posting → results

Proxy Callback Implementation

If you need to maintain brand consistency, set up a proxy callback on your domain that forwards requests to Outstand.

How It Works

  1. TikTok redirects to your callback: https://yourdomain.com/api/socials/tiktok/callback?code=...&state=...
  2. Your proxy endpoint forwards the request to Outstand: https://www.outstand.so/app/api/socials/tiktok/callback
  3. Outstand processes the OAuth flow and redirects back to your application

Implementation Examples

Next.js (App Router)

Create app/api/socials/tiktok/callback/route.ts:

import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
	const url = new URL(request.url);
	const outstandCallback = new URL('https://www.outstand.so/app/api/socials/tiktok/callback');
	
	// Forward all query parameters
	url.searchParams.forEach((value, key) => {
		outstandCallback.searchParams.set(key, value);
	});
	
	// Forward cookies from the original request
	const cookies = request.headers.get('Cookie') || '';
	
	try {
		// Forward the request to Outstand's callback
		const response = await fetch(outstandCallback.toString(), {
			method: 'GET',
			headers: {
				'Cookie': cookies,
			},
			redirect: 'manual', // Don't follow redirects automatically
		});
		
		// Get the redirect location from Outstand's response
		const location = response.headers.get('Location');
		
		if (location) {
			// Redirect user to Outstand's final destination
			return NextResponse.redirect(location);
		}
		
		// Fallback: redirect to Outstand callback directly
		return NextResponse.redirect(outstandCallback.toString());
	} catch (error) {
		console.error('Proxy callback error:', error);
		// Fallback: redirect to Outstand callback directly
		return NextResponse.redirect(outstandCallback.toString());
	}
}

Next.js (Pages Router)

Create pages/api/socials/tiktok/callback.ts:

import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
	const { query } = req;
	const outstandCallback = new URL('https://www.outstand.so/app/api/socials/tiktok/callback');
	
	// Forward all query parameters
	Object.entries(query).forEach(([key, value]) => {
		if (typeof value === 'string') {
			outstandCallback.searchParams.set(key, value);
		}
	});
	
	// Forward cookies
	const cookies = req.headers.cookie || '';
	
	try {
		const response = await fetch(outstandCallback.toString(), {
			method: 'GET',
			headers: {
				'Cookie': cookies,
			},
			redirect: 'manual',
		});
		
		const location = response.headers.get('Location');
		
		if (location) {
			return res.redirect(302, location);
		}
		
		return res.redirect(302, outstandCallback.toString());
	} catch (error) {
		console.error('Proxy callback error:', error);
		return res.redirect(302, outstandCallback.toString());
	}
}

Netlify Functions

Create netlify/functions/tiktok-callback.ts:

import type { Handler, HandlerEvent, HandlerContext } from '@netlify/functions';

export const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => {
	const queryParams = new URLSearchParams();
	
	// Forward all query parameters
	Object.entries(event.queryStringParameters || {}).forEach(([key, value]) => {
		if (value) {
			queryParams.set(key, value);
		}
	});
	
	const outstandCallback = `https://www.outstand.so/app/api/socials/tiktok/callback?${queryParams.toString()}`;
	
	// Forward cookies
	const cookies = event.headers.cookie || '';
	
	try {
		const response = await fetch(outstandCallback, {
			method: 'GET',
			headers: {
				'Cookie': cookies,
			},
			redirect: 'manual',
		});
		
		const location = response.headers.get('Location');
		
		return {
			statusCode: 302,
			headers: {
				'Location': location || outstandCallback,
			},
		};
	} catch (error) {
		console.error('Proxy callback error:', error);
		return {
			statusCode: 302,
			headers: {
				'Location': outstandCallback,
			},
		};
	}
};

Add to netlify.toml:

[[redirects]]
  from = "/api/socials/tiktok/callback"
  to = "/.netlify/functions/tiktok-callback"
  status = 200
  force = true

Express.js

const express = require('express');
const router = express.Router();

router.get('/api/socials/tiktok/callback', async (req, res) => {
	const outstandCallback = new URL('https://www.outstand.so/app/api/socials/tiktok/callback');
	
	// Forward all query parameters
	Object.entries(req.query).forEach(([key, value]) => {
		outstandCallback.searchParams.set(key, value);
	});
	
	// Forward cookies
	const cookies = req.headers.cookie || '';
	
	try {
		const response = await fetch(outstandCallback.toString(), {
			method: 'GET',
			headers: {
				'Cookie': cookies,
			},
			redirect: 'manual',
		});
		
		const location = response.headers.get('Location');
		
		if (location) {
			return res.redirect(302, location);
		}
		
		return res.redirect(302, outstandCallback.toString());
	} catch (error) {
		console.error('Proxy callback error:', error);
		return res.redirect(302, outstandCallback.toString());
	}
});

module.exports = router;

Vercel Serverless Function

Create api/socials/tiktok/callback.ts:

import type { VercelRequest, VercelResponse } from '@vercel/node';

export default async function handler(req: VercelRequest, res: VercelResponse) {
	const { query } = req;
	const outstandCallback = new URL('https://www.outstand.so/app/api/socials/tiktok/callback');
	
	// Forward all query parameters
	Object.entries(query).forEach(([key, value]) => {
		if (typeof value === 'string') {
			outstandCallback.searchParams.set(key, value);
		}
	});
	
	// Forward cookies
	const cookies = req.headers.cookie || '';
	
	try {
		const response = await fetch(outstandCallback.toString(), {
			method: 'GET',
			headers: {
				'Cookie': cookies,
			},
			redirect: 'manual',
		});
		
		const location = response.headers.get('Location');
		
		if (location) {
			return res.redirect(302, location);
		}
		
		return res.redirect(302, outstandCallback.toString());
	} catch (error) {
		console.error('Proxy callback error:', error);
		return res.redirect(302, outstandCallback.toString());
	}
}

Step 5: Obtain Your Credentials

Once your app is approved (or in sandbox mode):

  1. Navigate to your app in the TikTok Developer Portal
  2. Go to Basic Information
  3. You'll find:
    • Client Key: Your OAuth client key (public identifier)
    • Client Secret: Your OAuth client secret (keep this secure!)

Security Note: Your Client Secret is sensitive. Store it securely and never expose it in client-side code or public repositories.

Step 6: Add Credentials to Outstand

Once you have your Client Key and Client Secret, add them to Outstand:

Method 1: Using the API

curl -X POST https://api.outstand.so/v1/social-networks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "tiktok",
    "client_key": "YOUR_CLIENT_KEY_HERE",
    "client_secret": "YOUR_CLIENT_SECRET_HERE"
  }'

Method 2: Using the Dashboard

  1. Log in to Outstand Dashboard
  2. Navigate to SettingsSocial Networks
  3. Select TikTok from the dropdown
  4. Enter your Client Key
  5. Enter your Client Secret
  6. Click Add Social Network

Troubleshooting

OAuth Flow Fails

  • Check redirect URI: Ensure it exactly matches what's configured in TikTok (including trailing slashes)
  • Verify scopes: All 6 scopes must be enabled in your TikTok app
  • Check sandbox: If in sandbox mode, ensure test user is added

App Rejected by TikTok

  • Brand inconsistency: Use proxy callback solution to match redirect URI to your domain
  • Missing scope demo: Update demo video to show all enabled scopes
  • Invalid website: Ensure website URL is accessible and uses HTTPS

Scope Errors

  • Missing scopes: Enable all 6 scopes in TikTok app configuration
  • Scope mismatch: Ensure TikTok app scopes match what Outstand requests