RelayAPI
Guides

Connecting Accounts

Connect OAuth, per-instance, credential-based, and managed-bot accounts safely.

Connection models

RelayAPI supports four connection models. Use the platform-specific flow rather than placing provider credentials in a post request.

ModelPlatforms and endpointsWhat RelayAPI stores
OAuthMost social platforms through GET /v1/connect/{platform}Encrypted provider tokens and the selected provider identity
Per-instance OAuthMastodon through GET /v1/connect/mastodon?instance_url=...Encrypted token plus the immutable instance origin
Credential connectionsDiscord, Slack, SMS, Bluesky, newsletters, and direct WhatsApp flowsAn encrypted webhook, token, or app credential; validation strength is provider-specific
Managed bot challengeTelegram through POST /v1/connect/telegramThe selected chat ID; hosted users never provide a bot token

Workspace behavior

workspace_id is optional on every connection initiation flow unless your organization has Require Workspace ID enabled.

  • With Require Workspace ID disabled, omit workspace_id to create an organization-scoped connection. A key with at least one workspace grant can create and use organization-scoped connections.
  • With Require Workspace ID enabled, every new connection must include workspace_id; omission returns WORKSPACE_ID_REQUIRED.
  • A supplied workspace must be active, belong to the organization, and be allowed by the API key.
  • Reconnecting an existing provider identity never moves it silently. Omitting workspace_id preserves its current scope; supplying a different workspace returns ACCOUNT_WORKSPACE_CONFLICT.

RelayAPI revalidates the initiating key, its workspace grants, and the exact dashboard session (when applicable) before credentials are committed. A revoked session, disabled key, archived workspace, or changed workspace policy causes completion to fail without replacing the existing credential.

Connection-owned provider authority

A connected account's destination and provider identity are not ordinary editable annotations. Generic PATCH /v1/accounts/{id} metadata updates cannot replace connection-owned values such as a Mastodon/Listmonk instance origin, Bluesky PDS/DID/auth mode, WhatsApp Business Account ID, Beehiiv publication ID, Twilio sender/MMS capability, TikTok verified pull prefixes, or Snapchat's internal Public Profile verification marker.

The publisher uses the identity stored by the verified connection flow—for example, Beehiiv uses the connected platform_account_id publication and Listmonk uses the connected platform_account_id base URL. Reconnect the account, or use an explicit provider-selection endpoint where one is documented, to change that authority. Treat returned metadata as descriptive; never depend on a generic metadata patch to retarget stored credentials.

Standard OAuth

Start OAuth and redirect the user to the returned auth_url:

curl --get https://api.relayapi.dev/v1/connect/twitter \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  --data-urlencode "workspace_id=ws_example"

The one-time state binds the organization, initiating credential/session, selected workspace, and callback configuration. Do not construct, modify, or reuse it.

Set headless=true to receive a temporary polling token. Only the credential and dashboard session that started the flow can poll its result.

Scope upgrades and existing connections

An OAuth refresh preserves the grants attached to the existing authorization; it cannot silently add a newly requested scope. Reauthorize an existing connection before using a feature in this table:

PlatformRequired grantFeature that needs it
Xtweet.write, like.write, tweet.moderate.writePublished Post edits, like/unlike, and reply hide/unhide
Facebookpages_manage_posts, pages_manage_engagement, pages_messagingPage post/comment edits, like/unlike, comment hide/unhide, and Messenger read receipts
Instagraminstagram_manage_comments, instagram_manage_messagesComment hide/unhide and Instagram Messaging read receipts
TikTokvideo.uploadtarget_options.tiktok.publish_mode: 'inbox'
Threadsthreads_location_taggingtarget_options.threads.location_id
YouTubeyoutube.force-sslComment editing/moderation and video rating actions
Redditedit, voteEditing published self-text and post vote actions
WhatsApp embedded tokenwhatsapp_business_management, whatsapp_business_messagingWhatsApp administration, messaging, groups, usernames, block lists, and templates

This applies to connections created before those grants entered RelayAPI's authorization request. Starting a fresh OAuth flow and approving the updated permission screen is the only supported upgrade path; editing account metadata or waiting for token refresh does not expand authority.

Secondary selection

Facebook, LinkedIn, Pinterest, Google Business, and Snapchat require a page, organization, board, location, or Public Profile selection after OAuth. The pending response contains a connect_token; supply it to both the matching list and select endpoints.

curl --get https://api.relayapi.dev/v1/connect/snapchat/profiles \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  --data-urlencode "connect_token=$CONNECT_TOKEN"

The selection token is short-lived, operation-scoped, and bound to the initiating authority. It cannot inspect or complete another connection attempt.

TikTok verified media authority

TikTok OAuth snapshots the RelayAPI operator's configured TIKTOK_VERIFIED_URL_PREFIXES into the connected account. Those non-secret HTTPS domain prefixes must already be verified in the same TikTok developer app, and each path must end in / to preserve a slash-delimited authority boundary. They authorize TikTok PULL_FROM_URL for video and are mandatory for every photo URL; they are never accepted from a post caller.

The snapshot is immutable connection metadata. If an operator adds, removes, or changes a prefix, reconnect the TikTok account before relying on the new list. Videos outside the snapshot can still use RelayAPI's bounded FILE_UPLOAD path. See TikTok for the required creator choices, consent attestations, and source-mode behavior.

Mastodon per-instance OAuth

Mastodon requires the account's home instance as a bare public HTTPS origin:

curl --get https://api.relayapi.dev/v1/connect/mastodon \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  --data-urlencode "instance_url=https://mastodon.social"

RelayAPI checks the resolved destination, discovers same-origin OAuth metadata when available, registers an app on that instance, and returns its authorization URL. Paths, credentials, query strings, fragments, private/reserved addresses, and cross-origin OAuth endpoints are rejected.

The accepted instance becomes connection-owned metadata. A later post cannot override it with target_options, preventing a bearer token from being redirected to a caller-selected host. Reconnect a legacy account that reports MASTODON_RECONNECT_REQUIRED.

Discord webhook

Connect an incoming webhook with POST /v1/connect/discord:

curl -X POST https://api.relayapi.dev/v1/connect/discord \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "ws_example",
    "webhook_url": "https://discord.com/api/webhooks/123456789/secret-token"
  }'

Only the exact https://discord.com/api[/vN]/webhooks/{id}/{token} incoming-webhook form is accepted. RelayAPI calls Discord to verify that the credential exists, is an incoming webhook, and is bound to a channel before encrypting it. The URL is a bearer secret: never log it or place it in post content.

SMS through Twilio

Connect a Twilio account and an owned default sender with POST /v1/connect/sms:

curl -X POST https://api.relayapi.dev/v1/connect/sms \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "ws_example",
    "account_sid": "your-twilio-account-sid",
    "auth_token": "your-twilio-auth-token",
    "from_number": "+15017122661"
  }'

RelayAPI verifies that the Twilio account is active and that from_number is an SMS-capable number owned by it. The sender and its reported MMS capability become connection-owned metadata. Posts always use that verified sender; legacy target_options.sms.from_number is only a matching assertion and a mismatch returns SMS_SENDER_MISMATCH before provider I/O. RelayAPI's current SMS connector is Twilio-only.

Slack incoming webhook

Connect a Slack or GovSlack incoming webhook with POST /v1/connect/slack:

curl -X POST https://api.relayapi.dev/v1/connect/slack \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "ws_example",
    "webhook_url": "https://hooks.slack.com/services/T00000000/B00000000/secret"
  }'

RelayAPI validates the exact Slack-issued URL shape and stores it encrypted. Slack exposes no non-mutating incoming-webhook probe, so connection does not prove that the hook remains active or that channel policy permits a message. The first publish is the authoritative provider check. The webhook stays bound to the channel chosen when it was created; a post cannot override that channel.

Telegram managed bot

Initiate a 15-minute Telegram challenge:

curl -X POST "https://api.relayapi.dev/v1/connect/telegram?workspace_id=ws_example" \
  -H "Authorization: Bearer $RELAY_API_KEY"

Follow the returned instructions: add the named RelayAPI bot to the target channel/group, open a private chat with it, and send the challenge plus the target's public @username. The human sender must administer the chat. RelayAPI also verifies the managed bot itself: channels require administrator/creator status and can_post_messages; groups and supergroups require permission to send messages.

Poll with the same API key:

curl --get https://api.relayapi.dev/v1/connect/telegram \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  --data-urlencode "code=$TELEGRAM_CHALLENGE"

Challenges are one-time, organization-bound, and authority-bound. A private channel without a public @username cannot complete this challenge flow.

Credential lifecycle

  • OAuth state, selection tokens, headless polling tokens, and Telegram challenges are short-lived and single-operation capabilities. Start again after expiry or an authorization change.
  • RelayAPI refreshes provider tokens only when the provider issues a supported refresh credential. Provider revocation or lost scopes can require a new OAuth connection.
  • Reauthorize Facebook, TikTok, Threads, X, and Reddit connections created before the scope upgrades listed above when using their new operations.
  • Discord/Slack webhook rotation or deletion and Twilio Auth Token rotation are not refreshable. Reconnect the credential.
  • Restoring the managed Telegram bot's posting permission can resume publishing; changing the managed bot or target chat requires a new connection.
  • Changing TikTok verified URL prefixes requires reconnecting the TikTok account so the new authority is snapshotted.
  • Every Snapchat account connected before Public Profile verification markers were introduced must reconnect. Publishing and reconciliation fail closed with SNAPCHAT_RECONNECT_REQUIRED until a current connection verifies and selects the Public Profile.
  • Changing a Beehiiv publication or Listmonk origin requires reconnecting; generic account metadata cannot redirect either stored credential.
  • Disconnect an account with DELETE /v1/accounts/{id}. Treat provider-side revocation as a separate step unless the platform confirms that RelayAPI performed it.

See the Snapchat, TikTok, Mastodon, Discord, Slack, SMS, and Telegram pages for publishing behavior and provider-specific limits.

Found something wrong? Help us improve this page.

On this page