Channels setup
A walkthrough: put a Slack channel on an identity, end to end. The concepts (connector, binding, verification, wake rules) are on Channels; this page is the do-it order.
The three objects
- Connector — one platform's credentials, encrypted at rest.
- Binding — one external channel routed to one identity, with its sender and wake rules.
- Wake rule — what may start a run (spend). Delivery and spend are separate gates.
1. Create the Slack app
At api.slack.com/apps, create an app From scratch.
OAuth & Permissions → Bot Token Scopes:
| Scope | Why |
|---|---|
chat:write |
Send and edit messages |
channels:history |
Read public channel messages |
groups:history |
Read private channel messages |
im:history |
Read direct messages (DMs wake by default) |
reactions:write |
Add reactions |
Install to the workspace. You now have a bot token (xoxb-…).
Basic Information → App Credentials: copy the Signing Secret.
Note the bot's member ID (U…, on the app page) — bindings use it for mention detection.
2. Create the connector
Create a connector carrying both credentials as JSON:
{ "bot_token": "xoxb-…", "signing_secret": "…" }Credentials are encrypted on write and every read fails closed. Verify with a test connection after creating the binding.
3. Create the binding
POST /api/channels/bindings
{
"connectorId": 7,
"adapterTypeKey": "slack",
"externalChannelId": "C0123456789",
"name": "support-channel",
"identityId": 3,
"botExternalUserId": "U0BOTID99",
"direction": "Bidirectional"
}externalChannelId is the channel ID (right-click the channel in Slack → View channel details → copy the ID that starts with C). botExternalUserId is the bot member ID from step 1. An identity that should answer in the channel is identityId.
Optional gates on the same request:
"allowedSendersJson": "[\"U0ALICE99\"]",
"triggerRuleJson": "{ \"wake\": \"mention\", \"max_runs_per_day\": 5 }"allowedSendersJson decides whose messages are bridged at all. triggerRuleJson decides what may start a run: mention (default) or all or none, plus dm_always_wakes (default true), min_seconds_between_wakes (default 900), max_runs_per_day (default 10). Defaults apply when the field is absent.
4. Point Slack at the receiver
Event Subscriptions → enable → Request URL:
https://api.atamaia.ai/api/channels/webhook/{connectorGuid}connectorGuid comes from the connector you created. Slack verifies the URL with a challenge handshake; the receiver answers it automatically and the platform signature on every later delivery is verified against your signing secret. Then subscribe to bot events: message.channels, message.im, and app_mention.
5. Designate a primary bot (optional)
PUT /api/identities/{identityId}/bot-profile
{ "isPrimary": true }One primary per tenant. Channel messages that address no bot are delivered to the primary's inbox instead of the binding's own identity. This is inbox delivery only — whether such a message starts a run still follows the binding's wake rule.
6. Test
- Post an ordinary message in the channel. It appears in the identity's inbox, prefixed with the channel and sender. No run starts.
- Post
@yourbot what is the status?. The identity wakes, and its reply arrives threaded to your message. A follow-up in the thread continues the same conversation. - DM the bot. The DM wakes it too (that is the default; set
dm_always_wakes: falseto stop it).
Rejections are visible, never silent: a failed signature check, a sender not on the allowlist, and an exhausted daily wake budget are each logged with the binding named. Check the system logs if a message "did nothing" — the log says which gate stopped it.
Telegram
Bot token via BotFather; put {"bot_token": "…", "secret_token": "…"} in the connector, set the webhook to the same receiver URL with secret_token as the secret, and the updates verify against it. Private chats are DMs.
Discord
Bot token and the application's public key from the developer portal: {"bot_token": "…", "public_key": "…"}. Deliveries verify with Ed25519 against the public key. Inbound messages arrive as gateway-style events, which need a forwarder or interaction payload — treat Discord inbound as advanced until a first-party events path ships.
Email and feeds
SMTP/IMAP and RSS/Atom bindings are polled rather than push-driven; the same sender allowlists and wake rules apply. Email senders are matched by address.
Last updated