Channels
For developers who connect a client to OpenBot or extend its server. The examples need the access stated on this page. Start with the developer manual.
A Channel is one bot of your organization on one chat platform, such as a Slack app or a Telegram bot. People talk with the Bot of the Channel in direct chats and group chats. OpenBot stays headless: a Channel is a link between the platform and the API, not a user interface.
| Kind | Platform |
|---|---|
slack |
A Slack app with the Events API and interactivity. |
lark |
A Lark (Feishu) app with event subscription and card callbacks. |
telegram |
A Telegram bot. |
custom |
Any other system that speaks the Channel protocol of OpenBot. |
Every platform sends its events to a webhook, an OpenBot address that receives platform events. OpenBot checks the signature of each event, answers at once, and does the work later.
Add a Channel
Section titled “Add a Channel”See Set up Channels for provider settings.
Create with POST /v1/organization/channels and a commandKey. HTTP 201
returns the saved Channel; its executionId names the configuration work. A
change uses PATCH /v1/organization/channels/:channelId with commandKey and
expectedVersion. It returns the Channel. Reuse the key and body after a lost
reply. Read the execution to check remote registration.
Delete with DELETE /v1/organization/channels/:channelId and a JSON body
{ "commandKey": "remove-channel-1" }. HTTP 202 returns an execution receipt.
The Channel stops accepting new work. Removal waits for its saved work to
release resources, then removes the Channel and its links. Chats stay.
An upgraded Channel can have needsAuthorization: true. Its data and enabled
setting stay, but it starts no input or delivery work. Save a change, or rotate
its secret, with current rights to set its new caller. This clears the flag. An
old unknown send is not replayed as that new caller.
Link your account
Section titled “Link your account”The bot only works for members of the organization. When a person who is not linked writes to the bot, nothing runs. The bot sends them a link code instead. It sends the code where only that person sees it: in the direct chat, or as a private message in a group when the platform has them. A code lasts 15 minutes.
With linkPath, the bot sends a link such as
https://api.example.com/link?code=ocl_.... Your client on that path signs the
person in and then calls:
GET /v1/channel-links/:codeto show who the code is for.POST /v1/channel-links/:code/acceptto link the account to the caller. A code works only once.
The link needs a POST, so nobody can link an account by sending a person a
link alone. Without linkPath, the bot sends only the code, and the person
accepts it with the same calls.
GET /v1/user/channel-identities lists your linked accounts.
DELETE /v1/user/channel-identities/:channelId/:externalUserId unlinks one. An
administrator lists the people of a Channel with
GET /v1/organization/channels/:channelId/identities, and unlinks one with
DELETE on .../identities/:externalUserId.
Chats of a Channel
Section titled “Chats of a Channel”Each chat on the platform is one lasting Chat with kind: "channel": one Chat
for each direct chat and one for each group chat. The Chat has the name of the
chat as its title. List them with GET /v1/chats?kind=channel as the actor.
- In a direct chat, every message goes to the Bot.
- In a group chat, only a message that names the bot goes to the Bot. Each message starts with the name of the person who wrote it, so the Bot knows who speaks.
- A message from a person while the Bot works for that same person goes into the running Turn. The Bot reads it at its next step.
- A message from another person waits in the inbox of the Chat. It runs as its own Turn after the running Turn ends.
- While a Turn runs, the bot shows its text and changes the message as it grows. A long answer goes out in parts.
- The answer of every Turn goes to the chat. This is also true for a Turn that a notice starts, such as the result of work that the Bot gave away. So the Bot can say “I will look into it”, and post the result later.
- OpenBot drops an event that the platform sends a second time.
Each Turn works for its speaker
Section titled “Each Turn works for its speaker”A Turn works for the linked speaker. Its saved execution identity keeps the
speaker, the Chat owner, and the caller that set up the Channel. A token used to
set up the Channel keeps its limits after a restart. The core author field is
an input grouping key. Do not read a user ID from it.
- The speaker’s permissions limit what the Bot may do.
- Tools and plan steps in Channel work check Channel use rights. They do not give the speaker direct access to the owner’s stored Chat. App and Computer calls still check the rights on their own resources.
- The Channel caller’s limits also apply. The owner must still be allowed to use the Bot.
- Requests go to the speaker.
- The Bot uses the saved speaker identity for memory.
OpenBot checks the current member, token, Channel, and account link before work resumes or an outside call starts. Removing a link stops new acts for that speaker. A saved approval does not remove these checks.
Approvals in chat
Section titled “Approvals in chat”When a request waits for a person, the bot sends a card with three buttons:
Allow once, Allow in this chat and Deny. Allow in this chat
makes a Grant with the scope chat. See
Requests. Plans that wait for approval
in plan mode get the same card. The card goes to
the direct chat of the person when they linked an account on this Channel.
Otherwise it goes to the chat of the work. This is also true for a request from
work that the Bot gave away, such as a task Chat for this chat.
Only the person that the request waits for can press a button. When the request changes, the card shows the decision.
Bots can also post to another chat of the same Channel with the tool
openbot_channel_send. Each post is the capability channels.send, so the
chain of deciders decides it.
Execution and recovery
Section titled “Execution and recovery”Channel input, replies, cards, and tool posts use the common execution system. The webhook event ID drops repeats. A saved predecessor keeps the input order of each conversation on all nodes. The message and caller are sealed in product records. Engine messages hold only execution references.
Replies and cards read the execution event log. A restart reads from a cursor; it does not run a second scan for lost replies. Each text event has a step and an attempt. A model retry does not join text from two attempts.
Each message part and edit has a saved call intent and result. A known result is reused. If the platform may have taken a send but no result was saved, OpenBot pauses that execution. Use its events and decision endpoint to stop or allow another attempt. A network error alone does not prove that nothing was sent. Repeated decisions use the same command key.
openbot_channel_send returns queued and executionId. This means the post
was accepted. Observe that execution for the send result. Cancelling a stream
only closes the observer.
Custom Channels
Section titled “Custom Channels”A custom Channel connects any other chat system. Make it with credentials:
{ "kind": "custom", "endpoint": "https://chat.example.com/openbot" }. Then
make its signing secret with PUT /v1/organization/channels/:channelId/secret.
Send commandKey and the Channel’s expectedVersion in the body. The response
holds secret and channel. A retry with the same key returns the saved
result. A new command makes a new secret and stops the old one.
Both ways sign the same way. Each request has two headers:
X-OpenBot-Timestamp: the time in seconds.X-OpenBot-Signature:sha256=and the hex HMAC-SHA256 oftimestamp + "." + bodywith the secret.
Your system sends events to the webhookUrl:
{ "type": "message", "id": "evt_1", "conversation": { "id": "room-1", "kind": "group", "title": "Ops" }, "sender": { "id": "u_42", "name": "Ada" }, "text": "What broke last night?", "mentioned": true}id must be unique in the Channel. A button press is
{ "type": "action", "id", "conversation", "sender", "value" }.
OpenBot sends messages to the endpoint. A send has markdown, optional
buttons, and conversation, person or both. With both, only that person
should see it in that chat. With only person, it goes to a direct chat. Answer
with { "ref": "<message id>" }, and add conversation when OpenBot did not
send one. An edit has conversation, ref and the new markdown. OpenBot
only calls public addresses.
Permissions
Section titled “Permissions”| Resource | Action | What it allows |
|---|---|---|
Channel |
read |
Read the Channels of the organization and the people linked to them. |
Channel |
write |
Create, change and delete Channels, set their secrets, and unlink people. |
Channel |
use |
Talk with the Bot of a Channel, and let your Bots post to it. |
ChannelIdentity |
read |
Read your linked accounts. |
ChannelIdentity |
write |
Link and unlink your accounts. |
The path of a Channel is org / <org> / channel / <id>. Administrators manage
them. Every member may use them and link their own accounts. See
Permissions.
Errors
Section titled “Errors”| Error | Status | When |
|---|---|---|
ChannelInvalid |
400 | The Bot is not a shared Bot, the kind changed, or the platform refused the webhook. |
ChannelNotFound |
404 | There is no such Channel. |
ChannelLinkInvalid |
404 | The code is unknown, used or too old. Ask the bot again. |
ChannelIdentityNotFound |
404 | There is no such linked account. |
ChannelConflict |
409 | The Channel changed since you read it. |
ChannelHookDenied |
401 | The signature is wrong or too old, or the Channel is disabled. |
ChannelsUnavailable |
503 | OpenBot cannot reach its storage or the platform now. |