Skip to content

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.


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.

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:

  1. GET /v1/channel-links/:code to show who the code is for.
  2. POST /v1/channel-links/:code/accept to 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.


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.

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.


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.


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.


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 of timestamp + "." + body with 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.


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.


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.