Skip to main content
Account permissions limit what one connected account can do. A brand’s first account on a platform gets every permission the platform supports unless you send permissions. Send permissions when you connect an account to ask for less: the person connecting sees a shorter consent screen where the platform allows it, and the account can do only what you selected. Permissions are not API key scopes. A permission limits what a connected account can do on its platform and is written resource.action. A key scope limits what an API key can do in SocialAPI and is written resource:action. Connecting an account and changing its permissions cost no credits.

Endpoints

Connect with permissions

This request connects an Instagram account that can read and answer comments and nothing else:
Response (HTTP 202): the usual connect response, described in Connect accounts. After the person approves, GET /v1/accounts returns the account in data with both lists (other fields omitted):
permissions is a list of the names in The permissions. Duplicates collapse, and the lists are always in the order of that table.
  • Omitted. SocialAPI keeps the permissions of the brand’s existing account on that platform. A brand with none gets every permission. Reconnecting without permissions never changes them.
  • An empty list. The request returns 400 validation.permissions_empty.
  • An unknown name. The request returns 400 validation.permission_unknown, and error.meta.permission holds the name.
  • A name the platform has no use for. The request is accepted. The name stays in permissions and never appears in effective_permissions. For example reviews.read on Instagram.

The permissions

Permissions per platform

An account can use a permission only on a platform that supports it. The other names are accepted and ignored.
  • Follows the selection. The consent screen asks for the platform scopes of the permissions you selected. A platform scope that serves more than one permission can make the screen show more than you selected: Instagram asks for comments and for messages as 1 scope each, covering reading and writing. Facebook asks for messages as 1 scope, and asks for pages_read_user_content for both comments.read and comments.write. Pinterest asks for boards:read and pins:read for both posts.read and posts.write. Threads asks for publishing and deleting as 1 pair of scopes shared by posts.write and comments.write. X asks for tweet.write once for posts.write and comments.write. The account stays limited to your selection: an Instagram account connected with comments.read alone cannot reply to comments.
  • The same for every selection. The platform shows its fixed list of scopes. Google Business Profile asks for 3 identity scopes and 1 scope, business.manage, that covers all of its permissions. YouTube asks for 1 scope that covers everything. TikTok (except a creator connection), WhatsApp, and Zalo ask for no scope that depends on your selection. The account is still limited to your selection, and an account connected with reviews.read alone cannot reply to reviews.
  • No selection step. Telegram and Bluesky connect without a consent screen, so SocialAPI alone enforces your selection.
Each platform’s page lists the scopes it requests, under Scopes.

What an account can do right now

Every account has two lists: effective_permissions is permissions limited to what the platform supports and what the person connecting granted. The person can decline part of the consent screen, and a platform can withdraw access later. A call that needs a permission outside effective_permissions fails with 403 account.permission_missing, and error.meta.permission names it. The refusal comes before the call reaches the platform. A platform’s unsupported operation keeps its usual answer, 501 resource.not_supported, whatever the permissions. These calls answer differently:
  • Publishing (POST /v1/posts, POST /v1/posts/{pid}/publish, POST /v1/posts/{pid}/retry, and a scheduled post when it is delivered) reports account.permission_missing on the target and returns no 403.
  • Removing a published post from a platform. DELETE /v1/posts/{pid} reports the target in results with outcome: "failed" and leaves it published. POST /v1/posts/{pid}/unpublish returns 500 system.internal, and the target stays published.
  • Live post metrics (GET /v1/posts/{pid}/metrics) report resource.not_found on the target.
  • Stored lists. GET /v1/inbox/comments, GET /v1/inbox/conversations, and GET /v1/inbox/conversations/{id}/messages return what SocialAPI stored and never return account.permission_missing.
  • Review accounts. GET /v1/inbox/reviews does not check reviews.read.
A refused call costs what its path charges:
  • A comment reply, a DM, a review reply, and a mention reply cost no credit, because the check comes before the charge.
  • A post follows the post credit rules in Plans and usage.
  • Every other call is free.
An account without a permission also stops receiving what it covers:
  • Webhooks and Automations. Comments, mentions, messages, and reviews for a permission the account lacks are dropped: they do not reach your webhook endpoints, your Automations, or the inbox. With messages.write alone, the account still receives dm.status.read on Instagram, dm.status.delivered and dm.status.read on Facebook, and every dm.status.* event on WhatsApp. It receives no dm.sent and no dm.status.sent on Instagram or Facebook.
  • Posts. A post to an account without posts.write fails on its target with account.permission_missing, whether you publish it now or schedule it. For a scheduled post, the failure appears when the delivery runs.
  • Analytics. The account adds no new points to its stored analytics history.
When an account loses a permission you did not remove yourself, you receive an account.updated webhook with change set to permissions_reduced. Reconnect the account to ask for the permission again. On X, when X refuses a call because the account’s access lacks a scope, the call returns 403 platform.twitter.insufficient_scope. error.meta.scope names the scope when it is known (media.write for a media upload). The account does not become token_expired. When the scope is named, the permissions that need it leave effective_permissions until you reconnect the account: posts.write for media.write. Other platforms return their own platform.<name>.* code for the same refusal and do not change effective_permissions. POST /v1/invites takes the same permissions field. The account the person connects gets exactly that list, and on a platform whose consent screen follows the selection the person is asked only for what those permissions need.
Response (HTTP 201):
The response and every item of GET /v1/invites return permissions as you set it. null means you omitted it: when the link is used, SocialAPI applies the rule for an omitted permissions described in Connect with permissions.

Change an account’s permissions

PATCH /v1/accounts/{id} replaces an account’s permissions. permissions is required: send a list, or null to give the account every permission, including ones added later.
Response (HTTP 200): the account, with its new permissions and effective_permissions.
A request with no permissions field returns 400 validation.field_required. A value that is neither a list of strings nor null returns 400 validation.body_invalid. An empty list returns 400 validation.permissions_empty, and an unknown name returns 400 validation.permission_unknown. An ID that is not one of your accounts, or that a brand-restricted key cannot reach, returns 404 account.not_found.

Removing a permission deletes data

Removing a permission takes effect at once and deletes the data it covered. Adding the permission back does not restore the data.
If the deletion fails, the call fails and the permissions stay unchanged. Connecting the account again with a narrower permissions list deletes the same data. A permission the person declines on the consent screen when reconnecting leaves effective_permissions, and SocialAPI sends account.updated. It also deletes the same data, except on the first reconnect of an account connected before account permissions existed.

Adding a permission

Adding a permission takes effect at once when the platform already granted it to the account. Otherwise the permission appears in permissions but not in effective_permissions: reconnect the account so the person can grant it. Once a permission is in effective_permissions, the events it covers arrive again.

Automations

An Automation needs permissions on its account. Creating or updating it returns 400 validation.permission_missing when its trigger or actions need a permission outside the account’s effective_permissions, and error.meta.permission names it. An update is checked only when it changes steps or sets status to active. An Automation is not paused when its account later loses a permission: its actions fail on the Firing with account.permission_missing.

Errors

  • 403 account.permission_missing: the account does not have the permission the call needs. error.meta.permission names it. Add it with PATCH /v1/accounts/{id}, or reconnect the account when the platform has not granted it.
  • 400 validation.permission_unknown: a value in permissions is not a permission. error.meta.permission names it.
  • 400 validation.permissions_empty: permissions is an empty list.
  • 400 validation.permission_missing: an Automation needs a permission the account does not have. error.meta.permission names it.
  • 403 platform.twitter.insufficient_scope: X refused the call because the account’s access lacks a scope.
Every code is described in Errors.

Scopes

Invite endpoints need a full-access key. See Scoped API keys.

Events

account.updated with change: "permissions_reduced" fires when an account loses a permission you did not remove yourself. It does not fire when you remove a permission with PATCH /v1/accounts/{id}. The payload is in Webhook events.

Use from an AI agent

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