staqlydocs

Channels

Connect the accounts staqly publishes to, see which platforms are available and what each one allows.

Edit on GitHub

A channel is an account staqly publishes to: an X account, or your own automation when staqly should hand the post to a script or n8n workflow instead. The other platforms (LinkedIn, Mastodon, Telegram and more) are in the catalog as Soon. Connect a channel once; from then on every post can target it, and a collection's schedules can publish to it.

Connect a channel

Pick the platform

Open Channels in the sidebar and click Add channel. The drawer lists every platform staqly knows (the catalog below) in groups: your own automation, social networks, video and streaming, communities and chat, blogs and newsletters, business and portfolio. Platforms that are not ready yet carry a Soon badge and cannot be connected: not built yet, or an OAuth platform whose app keys the server doesn't have. A platform turned off on the server is not listed (see Platforms on a server).

Someone without access to Staqly (a client) can connect their account too: send them a connect link.

Connect it

How you connect depends on the platform's auth:

authWhat happens
tokenThe form asks for the platform's credentials (for example a bot token and chat id, or a handle and app password). Staqly checks them against the platform, reads the account's name and picture, and stores them sealed. No token platform is available in this release yet.
oauth2Connect with ... sends your browser to the platform; after you allow access it comes back to /channels/callback/<provider> and the channel is created. The platform needs a developer app whose keys are in the server's environment (.env); without them it is listed as Soon.
noneYour own automation: nothing to connect. Staqly asks your script or workflow to publish and waits for its result. See Your own automation.

Give the channel a Name (it defaults to the account's name) and, where the provider offers them, default settings for new targets (who can reply on X, say).

Use it

Pick the channel's avatar in the composer, or the channel in a schedule. The composer shows the platform's character limit per channel, gives each picked channel a tab for a text of its own and a folded Settings card under the editor with that platform's options (who can reply, a community, labels, a last comment, accounts that repost it...). Platforms that are not built yet already list their settings, so their posts can be prepared: Instagram (post as feed, reel or story, collaborators, first comment), TikTok (who can watch, comments, duets, stitches, AI and branded content labels), YouTube (title, visibility, made for kids, tags, category, playlist), LinkedIn (visibility), Pinterest (title, board, link, alt text), Reddit (title, subreddit, flair, NSFW, spoiler), Facebook (post, reel or story), Threads (who can reply), Dev.to and Medium (title, tags, original link), Lemmy (title, community, link). Each platform's page lists its settings.

From a terminal or a script, your own automation (and, once one is available, a token platform with its fields) connects with one request; OAuth platforms such as X only through the browser:

API=http://localhost:3333

# what each platform needs
curl -s -H "Authorization: Bearer $STAQLY_API_KEY" $API/v1/providers | jq '.data[] | {id, auth, status, credential_fields}'

# your own automation: staqly announces each post to your agents and webhooks
curl -s -H "Authorization: Bearer $STAQLY_API_KEY" -X POST $API/v1/channels -H 'Content-Type: application/json' \
  -d '{"provider":"custom","name":"My n8n publisher"}'

# your own automation that staqly calls itself (see Your own automation)
curl -s -H "Authorization: Bearer $STAQLY_API_KEY" -X POST $API/v1/channels -H 'Content-Type: application/json' \
  -d '{"provider":"custom","name":"My endpoint","fields":{"url":"https://n8n.example.com/webhook/staqly"}}'

Creating, changing and removing channels needs the channels:manage scope in cloud mode; listing them needs channels:read. Credentials are never returned by any call.

The catalog

GET /v1/providers (MCP list_providers, CLI staqly channels providers) lists every provider with its auth, status, limits, credential_fields and settings_fields. In this release Your own automation and X are available (X once the server has its app keys); every other platform is in the catalog as soon, so the dashboard already shows the whole grid and a post's preview can check the platform's limits.

ProvideridConnects withText limitMediaNeeds
Your own automationcustomnothing (none)noneup to 10 images, videos, GIFs or files—
X (available)xOAuth2804 pictures or 1 video—
LinkedInlinkedinOAuth3,0009—
LinkedIn Pagelinkedin_pageOAuth3,0009—
RedditredditOAuth40,0001a title
Instagram Business (through a Facebook Page)instagramOAuth2,20010media
Instagram (Instagram login, no Facebook Page)instagram_standaloneOAuth2,20010media
Facebook PagefacebookOAuth63,20610—
ThreadsthreadsOAuth50010—
YouTubeyoutubeOAuth5,0001 videoa title and the video
Google My Businessgoogle_businessOAuth1,5001 image—
TikToktiktokOAuth2,2001 videothe video
PinterestpinterestOAuth5001 imagea title, the image and a link
DribbbledribbbleOAuth1,0001 imagea title and the image
Discorddiscordtoken2,00010—
SlackslackOAuth40,00010—
KickkickOAuth500——
TwitchtwitchOAuth500——
MastodonmastodonOAuth5004—
Blueskyblueskytoken3004 images—
Lemmylemmytoken10,0001 imagea title
Farcasterfarcastertoken3202 images—
Telegramtelegramtoken4,09610—
Nostrnostrtokennone4 images—
VKvkOAuth16,00010—
Mediummediumtokennone1 imagea title
Dev.todevtotokennone1 imagea title
Hashnodehashnodetokennone1 imagea title
WordPresswordpresstokennone1 imagea title
ListMonklistmonktokennone—a title
Moltbookmoltbooktoken5,0004 images—
WhopwhopOAuth5,0004—
Skoolskooltoken5,0004 imagesa title
MeWemewetoken5,0004—
TumblrtumblrOAuth4,09610—

Platforms on a server

Every platform has a switch in the server's environment (.env), locally and in the cloud:

.env
PROVIDER_X_ENABLED=true            # false: turned off on this server
PROVIDER_X_CLIENT_ID=...           # OAuth platforms: the developer app
PROVIDER_X_CLIENT_SECRET=...
  • PROVIDER_<ID>_ENABLED=false hides the platform from the catalog and the dashboard and refuses connecting it and new posts on its channels (409 provider_disabled). Posts already scheduled on its channels still publish, and can still be edited.
  • Enabled but without _CLIENT_ID and _CLIENT_SECRET, an OAuth platform is listed as soon.
  • Restart the server after changing them. .env.example has a block for every platform.

All limits in one place: Limits.

"Media" means images and videos unless noted. The limits are the platforms' published ones and drive the composer's counters and GET /v1/posts/{id}/preview. Each platform gets its own page here when it becomes available, with what to register and which settings it takes.

Channel status and health

StatusMeaningWhat to do
ConnectedReady to publish.—
Needs reconnectA publish, a test or a token refresh failed with the stored credentials; the row shows the error. Targets on it fail until it is reconnected.Reconnect in the row's menu: OAuth platforms go through the platform again (the same account reconnects the existing channel), token platforms take fresh credentials (PATCH /v1/channels/{id} with fields).
DisabledTurned off by you. New posts cannot target it and schedules skip it.Enable in the menu (PATCH with status: connected).

Test connection (POST /v1/channels/{id}/test, MCP test_channel, CLI staqly channels test) checks the stored credentials against the platform now; a failing test marks the channel Needs reconnect, a passing one clears it. It is rate-limited (burst 5, then 10 per minute). OAuth sign-ins are refreshed by a refresh_channel job before they expire. The channel.needs_reconnect event is one of the three an alert sends by default.

Managing channels

The Channels page lists every channel with its picture, name, handle, platform, status and activity (last post, next post, posts in the last 30 days). Each row's menu has Settings, Test connection, Edit connection (platforms connected with fields, such as your own automation), Move to group (once there is more than one group), Disable or Enable, Reconnect (when it needs one) and Remove. Settings renames the channel, picks its group and sets Links in posts, what the channel does with the links in a post's text when it publishes:

Links in postshttps://example.com/a goes out as
Keep linksas written (the default on most platforms)
Remove linksnothing: the link is taken out
Show links as plain textexample[.]com/a, readable but not a link

Platforms that charge more for links or show posts with them to fewer people offer only the last two: X removes them unless you choose plain text. The post keeps its text; the character limit counts what the channel receives, the composer says in red which channels change which links, and GET /v1/posts/{id}/preview lists them per target (links_found, plus a warning). Over the API it is the channel's settings.links (the channel's links field shows the mode in use; the catalog's limits.links and limits.link_modes give each platform's default and choices).

Channel groups

Every channel belongs to exactly one group, for example one group per client. A workspace always has a Default group, which can't be deleted; new channels land there unless you pick another. With more than one group, the Channels page lists the channels group by group (each one folds open and closed), the composer's channel picker shows them under their group's name, and a group filter keeps one group. New group creates one, a group's menu renames it, and deleting a group moves its channels to Default.

Over the API: GET /v1/channel-groups lists the groups (Default first) with how many channels each holds; POST /v1/channel-groups creates one (name, unique in the workspace; optional color #rrggbb and position), PATCH /v1/channel-groups/{id} renames it, and DELETE /v1/channel-groups/{id} deletes it (409 default_group for Default). A channel's group_id says where it is; POST /v1/channels takes a group_id, PATCH /v1/channels/{id} with group_id moves it, and GET /v1/channels?group=grp_... keeps one group.

GET /v1/channels and GET /v1/channels/{id} also return each channel's activity, read from its targets: last_published_at and last_post_id (the last post that went out on it), next_publish_at (its next scheduled post) and published_30d. Webhook payloads carry the channel without it.

Removing a channel removes the targets on it from every post; posts with no other target become drafts.

GET/v1/channels · POST/v1/channels · GET/v1/channels/{id} · PATCH/v1/channels/{id} · DELETE/v1/channels/{id} · POST/v1/channels/{id}/test ·

GET/v1/channels/oauth/{provider}/start

Plan limits (cloud): 5 channels on Starter, 15 on Plus, 40 on Pro, unlimited on Business. Over the limit, connecting a channel answers 402 plan_limit_exceeded with details.limit = "channels". See Plans.

Security

  • Credentials and developer app secrets are sealed with AES-256-GCM. The key is generated into DATA_DIR/secret.key on first use, or comes from STAQLY_SECRET_KEY (32 bytes, base64). Back it up with the database: without it every channel has to be reconnected.
  • No response ever carries a credential or a client secret, not even to an admin.
  • The OAuth state is signed and bound to the browser that started the flow with a short-lived cookie, so a callback cannot be replayed into another session.
  • Publishing calls the platform from the server; your browser never holds a platform token.

Next steps

On this page