Skip to main content
A connected account is one social account (an Instagram account, a Facebook login with its Pages, a YouTube channel, a Telegram bot) that SocialAPI can act on for you. You start a connection with POST /v1/accounts/connect, send the person to the platform’s consent screen, and SocialAPI redirects them back to your app with the new account’s ID. SocialAPI keeps the platform’s access tokens, so you never receive or refresh them. The same flow serves every platform. Telegram and Bluesky skip the consent screen and connect in one request. Google Business Profile can pause so you choose which location to connect. Facebook connects every Page at once, and you can assign Pages to brands afterwards (see Facebook). Connecting, reconnecting, and disconnecting cost no credits.

Endpoints

Your first connection

This request starts connecting an Instagram account into an existing brand and asks SocialAPI to send the person back to your app afterwards:
Response (HTTP 202):
Send the person to auth_url. After they approve, their browser lands on your redirect_uri:
Store account_id against your user. The account is usable at once.

Request fields

Response fields

POST /v1/accounts/connect answers in one of two ways:
  • HTTP 202 for platforms with a consent screen: auth_url (send the person there), state (SocialAPI’s own value for this connection, needed only for POST /v1/oauth/exchange), and message. For WhatsApp, metadata carries the values your page needs to open Meta’s signup popup, and auth_url is empty. See WhatsApp.
  • HTTP 201 for Telegram and Bluesky, which connect without a consent screen: account_id, platform, username, and display_name.
The person has 1 hour from your request to finish on the platform. After 1 hour, the platform’s redirect reaches a SocialAPI error page instead of your redirect_uri, and you start a new connection.

How a connection works

A connection either completes at once, pauses for a choice of location, or fails. Every outcome reaches your redirect_uri as query parameters.
1

Start the connection

Call POST /v1/accounts/connect from your server with your API key. Pass the brand_id the account belongs in.
2

Send the person to the consent screen

Redirect the person’s browser to auth_url. They sign in to the platform and approve the scopes SocialAPI asks for. Each platform’s page lists those scopes.
3

Read the result on your redirect URI

SocialAPI completes the authorization with the platform and redirects the person to your redirect_uri with status and the parameters below. Check status first, then compare state with the value you sent.
4

Choose a Google Business Profile, if asked

When status is selection_required, no account exists yet. Read the candidates and choose within 30 minutes, as described in Choose a Google Business Profile.

Redirect parameters

error holds one of these values:
  • The platform’s own code when the person declines or the platform refuses the request, for example access_denied.
  • A platform.* or other SocialAPI error code when the platform or SocialAPI refuses the connection, for example billing.brands_limit (your plan’s brand allowance is used up), account.already_linked (the brand already holds a different account on this platform), account.different_login (the brand’s Facebook is connected through a different login), byok.credentials_missing (no X app credentials saved), byok.credentials_invalid (X rejected the saved credentials), or byok.app_access_denied (X refused your app access to its API). Each code is listed in Errors.
  • missing_code when the platform returned neither a code nor an error.
  • exchange_failed when the failure has no code.
After any error, start a new connection: the old auth_url is spent. Without a redirect_uri, a connection that needs a choice sends the person to the SocialAPI dashboard, which asks them to choose.

Platform slugs

The platform field takes one of these values: A slug not in this table, including trustpilot, returns 403 billing.platform_not_available. Which app each platform connects through (SocialAPI’s or your own) is listed in Platform apps.

Redirect URI rules

Your redirect_uri must use http or https and must not contain a user name, a password, or a #fragment. A malformed value returns 400 validation.redirect_uri_invalid_format. Until you register a redirect URI, SocialAPI accepts any well-formed redirect_uri. Once you register one or more, every redirect_uri must match one of them, and any other value returns 400 validation.redirect_uri_not_whitelisted before a connection starts. Register up to 20 redirect URIs in the dashboard at app.social-api.ai/api-configuration. Deleting every registered URI accepts any well-formed value again. SocialAPI compares redirect URIs after normalizing both sides: the scheme and host are lowercased, a default port (:443 for https, :80 for http) is dropped, a trailing / is removed, and query parameters are sorted. https://App.example.com:443/oauth/callback/ matches a registered https://app.example.com/oauth/callback. Your redirect_uri can carry its own query parameters. SocialAPI adds its parameters to them. When one of yours has the same name as a parameter SocialAPI sends (status, platform, state, account_id, account_ids, connection_id, error, error_description), SocialAPI’s value replaces yours.

Choose a Google Business Profile

A Google connection pauses with status=selection_required when the Google login manages more than one Business Profile. You choose exactly one. A login with a single Profile connects at once. The redirect carries only the connection_id. Read the candidates with GET /v1/accounts/pending/{connection_id}:
Response (HTTP 200):
Finish the connection by sending the chosen platform_account_id:
Response (HTTP 201):

Pending connection fields

Selection rules

  • A pending connection expires 30 minutes after it is created and works once. The first successful select consumes it. A second select, or a call after expiry, returns 404 resource.not_found.
  • A 400 keeps the pending connection. Fix the request and send it again within the 30 minutes.
  • A platform_account_id that is not in profiles[] returns 400 validation.profile_not_in_set.
  • A body without platform_account_id returns 400 validation.field_required.

Facebook Pages

A Facebook connection has no selection step. SocialAPI adds every Page the login granted that none of your other brands holds to the brand’s Facebook account, and the redirect carries status=success.
  • A login that grants no Page ends with status=error and error=platform.facebook.no_pages on your redirect_uri.
  • A login whose every Page belongs to another of your brands ends with status=error and error=platform.facebook.no_assignable_pages on your redirect_uri.
To assign a Page to another brand after connecting, see Facebook.

When reconnecting Facebook removes Pages

Facebook grants Page access per app, not per brand. When a person reconnects a Facebook login and unchecks a Page on Facebook’s consent screen, every brand that used that Page through this login loses it. The affected account gets status: reconnect_recommended with reconnect_reason: page_access_lost. The Page stays assigned to its brand. When the login grants the Page again (the person reconnects and keeps the Page checked), the Page works again on the same brand with no further step.

Finish a connection from your own page

POST /v1/oauth/exchange finishes a connection when your page, not SocialAPI, receives the authorization code. WhatsApp works this way: your page opens Meta’s signup popup and receives the code. The WhatsApp page has the full sequence.
Response (HTTP 201):
  • metadata.state is the state that POST /v1/accounts/connect returned. It works once, for 1 hour, and only with the API key that started the connection. An unknown, expired, or used state returns 400 validation.state_invalid. A state started with a different API key returns 403 auth.state_mismatch.
  • A missing platform or code returns 400 validation.field_required, and so does a missing metadata.state.
  • When one authorization connects more than one account, the response (HTTP 201) is {"data": [...], "count": 2} with one entry per account.
  • When the connection needs a choice, the response is HTTP 200 with "status": "selection_required", the connection_id, and the same profiles and login_id fields as GET /v1/accounts/pending/{connection_id}.

Account status

GET /v1/accounts returns every connected account with its status:
Response (HTTP 200):
Treat a reconnect_reason you do not recognize as a request to reconnect.

Reconnect an account

To reconnect an account, call POST /v1/accounts/connect again with the same platform and the account’s current brand_id (the brand_id that GET /v1/accounts returns), and send the person through the consent screen with the same platform login:
SocialAPI updates the existing account in place:
  • The account keeps its id, its brand, its posts, conversations, and Automations.
  • status returns to active and reconnect_reason is cleared.
  • The account keeps its permissions unless you send permissions on the reconnect. A narrower list deletes the data the removed permissions covered: see Removing a permission deletes data.
  • SocialAPI sends account.connected again.
Always pass brand_id when you reconnect. Without it, SocialAPI creates a new brand for the connection and moves the account into it, which leaves the old brand without the account. Connecting a platform account that another of your brands already holds moves it to the brand you name. These cases do not move it:
  • Facebook, and Instagram connected through Facebook Login. A Page or Instagram account that another of your brands holds is not taken. A login whose every Page or Instagram account belongs to another brand ends with error=platform.facebook.no_assignable_pages or error=platform.instagram.no_assignable_pages. You assign Pages to brands as described in Facebook.
  • Google Business Profile locations assigned with the assign call. POST /v1/platforms/google/logins/{loginId}/locations/{locationId}/assign returns 400 validation.location_already_assigned for a location that another brand holds. See Google locations.
  • lock_accounts_to_brand set to true on your SocialAPI account (PATCH /v1/users/me). A connect that would move an account to a different brand ends with error=account.already_linked, or returns 409 account.already_linked. The default is false. The lock does not apply to Facebook.
Each of those errors leaves the account in its current brand. A brand holds one connected account per platform. Connecting a different account of the same platform into a brand that already has one ends with status=error and error=account.already_linked on your redirect_uri. Telegram and Bluesky, which connect in one request, return 409 account.already_linked from POST /v1/accounts/connect, and so does POST /v1/accounts/pending/{connection_id}/select for a Google location. On Facebook, connecting a brand whose account came from a different Facebook login ends with error=account.different_login on your redirect_uri. A Google login with more than one YouTube channel connects every channel in one authorization, and the redirect carries every account in account_ids. Without brand_id, each channel connects into its own new brand named after the channel. With a brand_id, the brand takes one channel, and each further channel ends the connection with status=error and error=account.already_linked on your redirect_uri. Channels connected before the error stay connected.

Let someone else connect an account

An invite link lets a person who has no access to your SocialAPI account connect their own account to one of your brands. Agencies send it to clients. The link works once.
Response (HTTP 201):
Send url to the person. They approve on the platform’s consent screen, SocialAPI connects the account to the brand, and account.connected is sent to your webhook endpoints.
  • A brand_id that is not one of your brands returns 404 resource.not_found.
  • A brand that already holds an account on that platform, or that already has an unused, unexpired invite for that platform, returns 409 resource.conflict.
  • A Facebook invite connects every Page of the person’s login that none of your other brands holds. The person cannot choose Pages.
  • An expired, used, or revoked link shows the person a SocialAPI error page.
  • GET /v1/invites?brand_id={brand_id} lists the brand’s invites, newest first, each with id, platform, token, url, is_active, expires_at, created_at, and permissions. A missing brand_id returns 400 validation.field_required.
  • DELETE /v1/invites/{id} revokes an invite and returns HTTP 204 with no body. An unknown or already used invite returns 404 resource.not_found.
Creating, listing, and revoking invites needs a full-access key or the dashboard, and costs no credits.

Disconnect an account

DELETE /v1/accounts/{id} disconnects an account:
Response: HTTP 204 with no body. An ID that is not one of your accounts returns 404 account.not_found.
Disconnecting cannot be undone. Connecting the same platform account again creates a new account with a new id, and nothing below comes back.
Disconnecting an account:
  • Removes the account. It no longer appears in GET /v1/accounts, and every request with its ID returns 404 account.not_found. Its brand stays.
  • Deletes what SocialAPI stored for it: its Pages and board settings, its Automations and their run history, its DM conversations and messages, its comments and review replies, and the attachments received in its messages.
  • Removes the account from your posts. A post that targeted only this account is deleted. A post that also targeted other accounts keeps those targets.
  • Asks the platform to end SocialAPI’s access on Instagram, Facebook, Threads, Google Business Profile, YouTube, TikTok, X, and WhatsApp. The account is disconnected even when the platform does not answer. SocialAPI keeps the authorization while another connected account still uses the same platform login, so disconnecting one brand’s Facebook or Google account never cuts off another brand.
  • Leaves the authorization in place on LinkedIn, Pinterest, Zalo, and Bluesky, which offer SocialAPI no way to end it. The person removes SocialAPI from their platform settings (on Bluesky, deletes the app password). For Telegram, SocialAPI stops receiving the bot’s messages, and the bot token stays valid until you revoke it in @BotFather.
DELETE /v1/accounts/{id} does not send a webhook event.

Errors

POST /v1/accounts/connect refuses a request before the consent screen with these codes. Every code is described in Errors.
  • A missing platform returns 400 validation.field_required.
  • A state longer than 512 characters returns 400 validation.customer_state_too_long.
  • A slug not in the platform slugs table, including trustpilot, returns 403 billing.platform_not_available.
  • A request without brand_id when your plan’s brand allowance is used up returns 403 billing.brands_limit.
  • A brand_id that is not one of your brands returns 404 resource.not_found, with meta.resource set to brand. A brand_id that is one of your brands but outside your brand-restricted key’s brands returns 404 brand.not_found.
  • A malformed or unregistered redirect_uri returns 400 validation.redirect_uri_invalid_format or 400 validation.redirect_uri_not_whitelisted.
  • An empty permissions list returns 400 validation.permissions_empty, and an unknown permission name returns 400 validation.permission_unknown, with meta.permission naming it. POST /v1/invites returns both codes too.
  • X with no app credentials saved returns 412 byok.credentials_missing.
  • Telegram or Bluesky with a missing metadata field returns 400 validation.field_required, with meta.field naming it.
Errors after the consent screen reach your redirect_uri as status=error (see Redirect parameters).

Scopes

A brand-restricted key must pass a brand_id from its own list. A connection started without brand_id creates a new brand that the key cannot see. Invite endpoints need a full-access key. See Scoped API keys.

Events

  • account.connected is sent each time an account connects or reconnects.
  • account.updated with change: "permissions_reduced" is sent when an account loses a permission you did not remove yourself: see Account permissions.
  • account.disconnected is sent in two cases. When the person removes SocialAPI’s app from Instagram, Facebook, or Threads, SocialAPI disconnects and deletes the account as DELETE /v1/accounts/{id} does, and the event carries account_id, platform, and platform_user_id. When an account needs reconnecting, the account stays connected and the event carries reconnect_required: true and a reason.
The reason of a reconnect event names the cause. It equals reconnect_reason on GET /v1/accounts, with these exceptions:
  • access_revoked is sent for access_revoked itself, for password_changed, session_expired, invalid_access_token, app_not_installed, user_checkpointed, checkpoint_required, and user_not_confirmed, and for whatsapp_number_unavailable.
  • number_banned is sent for whatsapp_number_banned.
  • No event is sent for platform_unauthorized.
Payloads are in Webhook events.

Use from an AI agent

See MCP tools for every tool.
Last modified on October 19, 2026