Reelspan posts to a Slack channel through a Slack app of your own. You connect it one of two ways, and the way decides what a post can carry.
What you can post
| Post | With a webhook | With a bot token |
|---|---|---|
| Text | A message | A message, with links unfurled |
| Photos | A message with up to 10 images, which Slack fetches and keeps | Up to 10 photos uploaded into the channel, with the text as their message |
| Video | A message with a link to the video, valid for 7 days, and a warning | The video uploaded into the channel, with the text as its message |
Use a webhook when you post text and photos and want the quickest setup. Use a bot token when you post videos, or want files to live in Slack.
With a bot token, the result's url is the message or file's permalink, and file_ids lists the uploaded files. A webhook doesn't answer with the message, so url and post_id are null.
Connect your channel
With a webhook
Setup takes about three minutes.
- Create a Slack app for your workspace: Create New App → From scratch.
- In the app, open Incoming Webhooks and turn them on.
- Click Add New Webhook, pick the channel and allow. Copy the webhook URL.
- In the Reelspan dashboard, open Accounts → Connect account, choose the profile and Slack, pick Webhook, and paste the URL. Add the channel's name if you want it shown in Reelspan.
Reelspan checks the webhook without posting anything: Slack answers an empty message with no_text when the hook is live.
With a bot token
- Create a Slack app for your workspace: Create New App → From scratch.
- Under OAuth & Permissions, add the bot scopes
chat:write,files:write,channels:readandchannels:join, then Install to Workspace. - Copy the Bot User OAuth Token (
xoxb-…). For a private channel, invite the bot there first:/invite @yourbot. - In the Reelspan dashboard, choose Bot token and paste the token and the channel: its name (
#announcements) or its id (C…) from the channel details.
Reelspan checks the token, finds the channel, and joins it if it's public and the bot isn't in it yet. Credentials are stored encrypted.
With the API
Send either pair to POST /v1/accounts/slack. When both are present, the webhook is used.
# a webhook
curl -X POST https://api.reelspan.com/v1/accounts/slack \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX", "name": "#announcements"}'
# or a bot token
curl -X POST https://api.reelspan.com/v1/accounts/slack \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "bot_token": "xoxb-...", "channel": "#announcements"}'import { Reelspan } from 'reelspan';
const reelspan = new Reelspan();
// a webhook
await reelspan.accounts.connect('my-brand', 'slack', {
webhook_url: process.env.SLACK_WEBHOOK_URL,
name: '#announcements',
});
// or a bot token
await reelspan.accounts.connect('my-brand', 'slack', {
bot_token: process.env.SLACK_BOT_TOKEN,
channel: '#announcements',
});import os
from reelspan import Reelspan
reelspan = Reelspan()
# a webhook
reelspan.accounts.connect("my-brand", "slack", webhook_url=os.environ["SLACK_WEBHOOK_URL"], name="#announcements")
# or a bot token
reelspan.accounts.connect("my-brand", "slack", bot_token=os.environ["SLACK_BOT_TOKEN"], channel="#announcements"){ "success": true, "platform": "slack", "account": "#announcements", "reconnected": false }| Field | Method | Meaning |
|---|---|---|
webhook_url |
Webhook | The Incoming Webhook URL (https://hooks.slack.com/services/…) |
name |
Webhook | Optional. How the channel shows in Reelspan |
bot_token |
Bot token | The bot token (xoxb-…) |
channel |
Bot token | The channel's name or id. name is used when channel is empty |
The field names are the same as Upload-Post's. Connecting again replaces the Slack account on that profile. See Connect with credentials.
Example post
A video, uploaded into the channel (bot token):
curl -X POST https://api.reelspan.com/v1/posts/video \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=slack" \
-F "title=Launch day" \
-F "slack_title=The launch video is ready. Share it with your teams." \
-F "[email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const post = await reelspan.posts.video({
user: 'my-brand',
platforms: ['slack'],
title: 'Launch day',
video: { data: await readFile('launch.mp4'), name: 'launch.mp4', type: 'video/mp4' },
extra: { slack_title: 'The launch video is ready. Share it with your teams.' },
});from reelspan import Reelspan
reelspan = Reelspan()
post = reelspan.posts.video(
"my-brand", ["slack"], "launch.mp4", "Launch day",
extra={"slack_title": "The launch video is ready. Share it with your teams."},
)Fields
| Field | Meaning |
|---|---|
slack_title |
The message text on Slack. Falls back to title. |
title |
The caption every network uses, when slack_title isn't sent. |
slack_alt_text |
Webhook only: alt text for the images. One text for all, or one per image. Falls back to alt_text. |
alt_text |
The alt text for every network that takes it. |
Slack has no options of its own in the dashboard composer. Slack posts can't take a first comment; a first_comment comes back as "first_comment": "unsupported" with a warning.
Limits and behaviour
- Text: up to 40,000 characters; anything longer is dropped without a warning. With a webhook, the message block shows the first 3,000.
- Files (bot token): up to 1 GB each, and up to 10 per post.
- Images (webhook): up to 10. Slack fetches each from a link that works for 7 days and keeps its own copy.
- Videos (webhook): a webhook can't carry files, so the video goes as a link that works for 7 days, and the result carries a warning. Connect with a bot token to upload it.
- Formatting: webhook messages use Slack's
mrkdwn.
Common errors
| Code | When | Fix |
|---|---|---|
INVALID_WEBHOOK |
Connecting: the URL isn't a Slack Incoming Webhook, or Slack doesn't accept it | Copy it again from the app's Incoming Webhooks page. Check the channel still exists. |
INVALID_TOKEN |
Connecting: the token doesn't start with xoxb- |
Use the Bot User OAuth Token, not a user token. |
CHANNEL_NOT_FOUND |
Connecting: the bot can't see a channel by that name | Check the name, or use the channel's id. Invite the bot to a private channel. |
NOT_IN_CHANNEL |
Connecting: the bot isn't in a private channel, or couldn't join a public one | /invite @yourbot in the channel, or add the channels:join scope. |
MISSING_FIELD |
Connecting with neither a webhook URL nor a bot token | Send webhook_url, or bot_token and channel. |
reauth_required |
The token was revoked, or the webhook removed or its channel archived | Connect again. When connecting, this shows as REAUTH_REQUIRED. |
file_too_large |
A file is over 1 GB | Send a smaller file. |
slack_error |
Slack refused the call. Its reason is in error, with a hint for not_in_channel, channel_not_found and missing_scope. Retried automatically on 429 and 5xx |
Follow the hint, then retry. |
Errors when connecting come back as a 400 with the code in error_code. Errors when posting are in that network's result. See Errors.