Skip to main content

Connect API — Build Your Own Connect Page

The Connect API lets you build the "connect your social accounts" experience inside your own product, on your own domain, with your own design — instead of sending end users to the hosted access_url page described in the White-label Integration Guide.

Your page requests a platform authorize URL from Upload-Post, redirects the end user to the social network's consent screen, and Upload-Post handles the OAuth exchange and token storage. After the connection completes, the user is sent back to the URL you choose.

When to use which:

Hosted page (access_url)Connect API (this page)
Setup effortNone — one API callYou build the UI
BrandingLogo, title, colors, language100% yours — it's your page
Domain the user seesapp.upload-post.comYours (except the OAuth hops)

Note: During the OAuth flow the user always visits the social network's own consent screen, and the network redirects briefly through app.upload-post.com (the OAuth callback registered with each platform) before returning to your redirect_url. This hop lasts milliseconds and is required by the platforms' OAuth policies — it applies to every provider in the industry.

How it works

Your backend                Your connect page             Upload-Post              Social network
│ │ │ │
│ 1. generate-jwt (API key) │ │ │
│───────────────────────────>│ │ │
│ profile JWT │ │ │
│ │ 2. POST /oauth/<platform>/start (profile JWT) │
│ │───────────────────────────>│ │
│ │ authorize_url + state │ │
│ │ 3. redirect user ──────────────────────────────────>│
│ │ │ 4. user authorizes │
│ │ │<── code + state ───────│
│ │ │ 5. token exchange, │
│ │ │ account stored │
│ │<── 6. redirect to your redirect_url ────────────────│
  1. Your backend calls generate-jwt with your API key to obtain a profile token for the end user's profile.
  2. Your connect page calls the start endpoint below with that profile token and receives the authorize_url.
  3. You redirect the user to authorize_url (the social network's consent screen).
  4. After consent, the network redirects to Upload-Post's registered callback, which completes the exchange — authenticated by the single-use state, so the user's browser needs no session with Upload-Post.
  5. The user lands back on your redirect_url with ?connect_status=success&platform=<platform>.

Start endpoint

POST /api/uploadposts/oauth/{platform}/start

Supported platforms: tiktok, instagram, facebook, linkedin, youtube, x (alias: twitter), threads, reddit, pinterest, google-business, snapchat

Authentication

Any of:

  • Profile JWT (recommended for browser calls): Authorization: Bearer PROFILE_JWT — the token from generate-jwt. The profile is taken from the token.
  • API key (server-to-server): Authorization: Apikey YOUR_API_KEY — pass the profile in the body.

Never expose your API key in a browser; use the profile JWT there.

Request body

FieldTypeRequiredDescription
profilestringOnly with API key authProfile username the connected account will be linked to. Ignored when a profile JWT is used.
redirect_urlstringNoAbsolute http(s) URL (max 2000 chars) to send the end user back to after a successful connection. ?connect_status=success&platform=<platform> is appended.

Response

{
"success": true,
"platform": "instagram",
"authorize_url": "https://www.instagram.com/oauth/authorize?client_id=...&state=...",
"state": "e34zUEyZjWy6EFeI7IzGSEiUfY8O4K4_",
"expires_in": 900
}

Redirect the end user to authorize_url within 15 minutes (expires_in) — the underlying state is single-use and expires after that window. Mint a fresh one per connection attempt.

Example — browser (profile JWT)

const resp = await fetch(
'https://api.upload-post.com/api/uploadposts/oauth/instagram/start',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${profileJwt}`,
},
body: JSON.stringify({
redirect_url: 'https://yourapp.com/social/connected',
}),
}
);
const { authorize_url } = await resp.json();
window.location.href = authorize_url;

Example — server (API key)

curl -X POST "https://api.upload-post.com/api/uploadposts/oauth/tiktok/start" \
-H "Authorization: Apikey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profile": "end-user-123",
"redirect_url": "https://yourapp.com/social/connected"
}'

Errors

StatusMeaning
400Missing profile (API key auth) or invalid redirect_url
401Missing or invalid authentication
404Unknown platform, or profile not found for this account (error_code: PROFILE_NOT_FOUND)
500Platform client not configured on the server

Handling the return

On success the end user arrives at your redirect_url:

https://yourapp.com/social/connected?connect_status=success&platform=instagram

To confirm the connection server-side (recommended), call GET /api/uploadposts/users and check the profile's social_accounts.

If the user cancels on the consent screen or the connection fails, they remain on the Upload-Post error screen with a human-readable message; they can simply retry from your page with a freshly minted start.

Security model

  • The state in the authorize URL is a 192-bit random value stored server-side, single-use and valid for 15 minutes. It is what authenticates the OAuth callback, so the end user's browser never needs an Upload-Post session.
  • The state is bound to the platform, profile and account that minted it — it cannot be replayed, reused across platforms, or combined with another account's session.
  • OAuth secrets (PKCE verifiers for TikTok and X) never leave the server; only the S256 challenge appears in the authorize URL.
  • redirect_url is validated to be an absolute http(s) URL and is only used after a successful connection.

Notes per platform

  • youtube: profiles configured with custom YouTube credentials authorize against their own Google client automatically.
  • x / twitter: both names are accepted; responses always report platform: "x".
  • snapchat: connection is limited to basic profile scopes (posting requires Snapchat Public Profile API approval).
  • instagram: the end user's Instagram must be a Business or Creator account, same as the hosted flow.