Connect a social account
Kicks off the OAuth flow for a platform. Synposter gives you an authorization URL that you redirect the end user to. Once they approve, Synposter exchanges the authorization code for OAuth tokens behind the scenes, stores them safely encrypted, and registers the new connected account under the profile you chose, so you never have to handle access tokens or refresh logic yourself.
The flow
- 1
Your backend asks Synposter for an authorization URL
Your server sends a
POSTto/v1/connect/{platform}with the profile that the new connected account should belong to. You can optionally include aredirectUriof your own; if you omit it, Synposter will send the end user to its own hosted confirmation page once the flow finishes, which is useful for command-line tools and other headless integrations. - 2
Synposter responds with an authorization URL
The response includes a single field,
authUrl, that points to the platform's authorization page. Your server redirects the end user's browser there. - 3
The end user authorizes the connection on the platform
The user signs in to the platform if they aren't already signed in, reviews the permissions Synposter is requesting, and approves the request.
- 4
The platform sends the user back to Synposter
Once the user approves, the platform redirects their browser to Synposter's callback URL. Synposter exchanges the authorization code for OAuth access and refresh tokens, encrypts them at rest, and stores them as a new connected-account record under the profile you chose in the first step.
- 5
Synposter sends the user back to your application
Finally, Synposter redirects the user's browser to your
redirectUri, appendingprofileId,accountId,platform,handle, and the originalstatevalue you sent (if any) as query parameters so your application knows which connection just completed. If you didn't supply aredirectUri, the user instead lands on Synposter's built-in success page and can simply close the window.
Request
curl -X POST https://api.synposter.com/v1/connect/twitter \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "9b3a...",
"redirectUri": "https://yourapp.com/connected",
"state": "your-end-user-id"
}'Body
| Field | Type | Required | Description |
|---|---|---|---|
| profileId | string | No | Profile to attach the connected account to. If omitted, your default profile is used. |
| redirectUri | string | No | Where to send the user after the OAuth flow completes (success or failure). Must use either http:// or https:// — other schemes (javascript:, data:, file:, etc.) are rejected with 400 invalid_redirect_uri. If omitted, the user lands on a Synposter-hosted success page, useful for CLI tools and other headless integrations. |
| state | string | No | Opaque value echoed back to your redirectUri. Use it to correlate the connection with your end user (e.g. their ID in your DB). |
Response (200)
{
"authUrl": "https://x.com/i/oauth2/authorize?response_type=code&client_id=..."
}Redirect the end user's browser to authUrl, typically a 302 from your server.
Status codes
| 200 | Auth URL returned. |
| 400 | Returned with one of invalid_json (the request body wasn't valid JSON or didn't parse to an object) or invalid_redirect_uri (the redirectUri wasn't a parseable URL or wasn't http(s)). |
| 401 | The API key was missing or invalid. |
| 404 | Returned with profile_not_found (the profileId doesn't exist or belongs to a different developer; same code in both cases for leak-proofness) or no_profile_found (you didn't pass a profileId and your account has no default profile). |
| 500 | Returned with internal_error (Synposter is misconfigured or a database lookup failed) or failed_to_persist_state (we couldn't write the OAuth state row). Safe to retry. |
Final redirect to your app
On success, Synposter redirects the user's browser to:
{your redirectUri}?profileId=...&accountId=...&platform=twitter&handle=...&state=...Query parameters on success
| Field | Type | Required | Description |
|---|---|---|---|
| profileId | string | Yes | Profile the account was attached to. |
| accountId | string | Yes | ID of the new connected account. |
| platform | string | Yes | e.g. "twitter". |
| handle | string | No | Platform-side username. |
| state | string | No | The same value you passed in the request body, echoed back so you can correlate this redirect with the original connect call (e.g. your end-user ID). Only present if you sent one. Not Synposter's internal CSRF nonce. |
On error
On any failure (user declined, token exchange failed, state expired, etc.) Synposter still redirects to your redirectUri but with an error param instead of accountId:
{your redirectUri}?error=token_exchange_failed&state=...| Field | Type | Required | Description |
|---|---|---|---|
| access_denied | string | No | User declined on the platform consent screen. |
| missing_code | string | No | Platform redirected without an auth code. |
| state_expired | string | No | More than 10 minutes passed between connect and callback. |
| token_exchange_failed | string | No | Platform rejected the auth code. |
| user_lookup_failed | string | No | Couldn't fetch the connected user's profile after token exchange. |
| persist_failed | string | No | Internal database error storing the tokens. |
| internal_error | string | No | Synposter is misconfigured (typically a missing platform credential). Capture the x-request-id and contact support. |
| platform_error | string | No | Generic catch-all for any other OAuth 2 error code the platform returned (invalid_request, invalid_scope, server_error, temporarily_unavailable, unauthorized_client, unsupported_response_type). The original code is preserved verbatim only for the access_denied case; everything else is collapsed to platform_error so we never reflect arbitrary platform-supplied text into your redirect URL. Check the Synposter logs by request id for the raw cause. |
For triage, every response from POST /v1/connect/{platform} includes an x-request-id header. Capture it on your backend before redirecting the user, and share it with support if a connection fails. We can trace the full chain (auth, profile lookup, token exchange, database write) from that single ID.
Platform OAuth apps
You don't need to register your own OAuth app with each platform. Synposter already has its own apps registered and receives the platform's callback at /api/callback/{platform}. Your redirectUri is optional: if you supply one, Synposter forwards the user there after the handshake completes; if you omit it, the user lands on a Synposter-hosted success page instead, useful for CLI tools and other headless integrations.