Twelve networks connect with credentials the account owner makes on the network, instead of an OAuth sign-in. Send them to POST /v1/accounts/{platform} with the profile in profile_username. Reelspan checks them with the network first, saves them encrypted, and answers with the account it connected.
For the other ten networks, use the OAuth sign-in instead: see Connecting accounts.
Examples
Telegram
Create a bot with @BotFather, add it to your channel as an admin that can post, then send its token and the channel. A public channel is its @name; a private one is its numeric id, which starts with -100.
curl -X POST https://api.reelspan.com/v1/accounts/telegram \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "bot_token": "123456789:AAH…", "chat": "@mybrandchannel"}'import { Reelspan } from 'reelspan';
const reelspan = new Reelspan();
await reelspan.accounts.connect('my-brand', 'telegram', { bot_token: process.env.TELEGRAM_BOT_TOKEN, chat: '@mybrandchannel' });import os
from reelspan import Reelspan
reelspan = Reelspan()
reelspan.accounts.connect("my-brand", "telegram", bot_token=os.environ["TELEGRAM_BOT_TOKEN"], chat="@mybrandchannel")Bluesky
Use an app password (Bluesky: Settings → Privacy and security → App passwords), never your main password.
curl -X POST https://api.reelspan.com/v1/accounts/bluesky \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "identifier": "mybrand.bsky.social", "app_password": "abcd-efgh-ijkl-mnop"}'await reelspan.accounts.connect('my-brand', 'bluesky', { identifier: 'mybrand.bsky.social', app_password: process.env.BLUESKY_APP_PASSWORD });reelspan.accounts.connect("my-brand", "bluesky", identifier="mybrand.bsky.social", app_password=os.environ["BLUESKY_APP_PASSWORD"])WordPress
In your WordPress admin, open Users → Profile → Application Passwords (WordPress 5.6 or later, on https) and create one for Reelspan.
curl -X POST https://api.reelspan.com/v1/accounts/wordpress \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "site": "blog.example.com", "username": "editor", "app_password": "abcd efgh ijkl mnop qrst uvwx"}'await reelspan.accounts.connect('my-brand', 'wordpress', { site: 'blog.example.com', username: 'editor', app_password: process.env.WP_APP_PASSWORD });reelspan.accounts.connect("my-brand", "wordpress", site="blog.example.com", username="editor", app_password=os.environ["WP_APP_PASSWORD"])The response
{ "success": true, "platform": "telegram", "account": "@mybrandchannel", "reconnected": false }account is how the connected account is named. reconnected is true when the profile already had an account on this network: the new credentials replace it.
Fields per network
Each field also accepts the name in the Also accepted column, so calls written for Upload-Post work unchanged. When both are sent, the Reelspan name wins.
| Network | Field | Also accepted | Required | What it is |
|---|---|---|---|---|
bluesky |
identifier |
handle |
Yes | Your handle (like mybrand.bsky.social) or account email |
app_password |
password |
Yes | An app password, not your main password | |
telegram |
bot_token |
Yes | The token @BotFather gave you, like 123456789:AAH… |
|
chat |
chat_id |
Yes | @name of a public channel, or the numeric id of a private channel or group |
|
discord |
webhook_url |
Yes | The channel's webhook: channel settings → Integrations → Webhooks | |
slack |
webhook_url |
One way | An incoming webhook URL (https://hooks.slack.com/services/…) |
|
name |
No | How the channel shows in Reelspan, with a webhook | ||
bot_token |
Other way | A bot token (xoxb-…) with chat:write, files:write, channels:read and channels:join |
||
channel |
With bot_token |
The channel's name or id (C…) |
||
mastodon |
server |
instance_url |
Yes | Your server, like mastodon.social |
access_token |
Yes | From Preferences → Development → New application, with read and write |
||
wordpress |
site |
site_url |
Yes | Your site's address |
username |
Yes | Your WordPress username | ||
app_password |
application_password |
Yes | An application password, not your login password | |
devto |
api_key |
Yes | From Settings → Extensions → DEV Community API Keys | |
hashnode |
token |
pat |
Yes | A personal access token from Account settings → Developer |
blog |
publication_id |
No | The blog's address or publication id; needed only with more than one blog | |
lemmy |
server |
instance_url |
Yes | Your server, like lemmy.world |
community |
Yes | The community name, or name@server for one on another server |
||
username |
Yes | An account that may post in the community | ||
password |
Yes | Used once to get a token; it isn't kept | ||
listmonk |
server |
instance_url |
Yes | Your Listmonk address |
user |
username |
Yes | An API user (Listmonk 4+), or the admin username | |
token |
password |
Yes | The API user's token, or the admin password | |
list |
list_id |
Yes | The list's name or id | |
whop |
api_key |
Yes | A company API key with forum:read, forum:post:create and file permissions |
|
forum |
experience_id |
One of these | The forum's experience id (exp_…) |
|
company_id |
One of these | The company id (biz_…), to post to its public forum |
||
nostr |
nsec |
private_key |
Yes | Your private key, nsec1… (or 64 hex characters) |
relays |
No | wss:// relays, as a list or separated by spaces |
Slack has two ways in. A webhook is quickest: messages and photos post into the channel, and a video or file goes as a link. A bot token uploads videos, photos and files into the channel itself; for a private channel, invite the bot first with /invite @yourbot.
Nostr without relays publishes to relay.damus.io, nos.lol and relay.primal.net. Media is hosted on nostr.build.
Values can be strings, numbers (a Telegram chat id, for example) or lists of strings; a list is joined with spaces.
Errors
| Status | error_code |
When |
|---|---|---|
| 400 | MISSING_FIELD |
A required field is missing. The message names it. |
| 400 | A code for the problem, such as INVALID_TOKEN, INVALID_WEBHOOK or BOT_NOT_ADMIN |
The credentials are malformed or the network refused them. The message says what to fix. |
| 403 | PLATFORM_DISABLED |
Connecting this network is switched off for now. |
| 403 | PROFILE_FORBIDDEN |
The key is limited to other profiles. |
| 404 | PROFILE_NOT_FOUND |
No profile has that username. |
| 429 | RATE_LIMITED |
More than 30 connection attempts from your workspace in 10 minutes. |
Each attempt reaches the network, which is why attempts are capped. Calls need a key with the profiles scope.
Disconnect
DELETE /v1/accounts removes one network from a profile, for credentials and OAuth networks alike. It deletes the stored credentials and fires the social_account_disconnected webhook. Disconnecting a network that isn't connected also answers 200.
curl -X DELETE https://api.reelspan.com/v1/accounts \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "social_platform": "telegram"}'await reelspan.accounts.disconnect('my-brand', 'telegram');reelspan.accounts.disconnect("my-brand", "telegram"){ "success": true, "message": "telegram disconnected" }When nothing was connected, the message is telegram was not connected.