Table of Contents

Note: Documentation for the legacy, pre-rebrand Cisco Spark version of Botkit is here.

  1. Install Botkit on your computer

  2. Create a Botkit powered Node app:

    botkit new --platform webex
  3. Follow this guide to configuring the Cisco Webex Teams API

Botkit receives messages from the Cisco Webex cloud platform using webhooks, and sends messages using their APIs. This means that your bot application must present a web server that is publicly addressable. Everything you need to get started is already included in Botkit.

To connect your bot to Webex, get an access token here. In addition to the access token, Webex bots require a user-defined secret which is used to validate incoming webhooks, as well as a public_address which is the URL at which the bot application can be accessed via the internet.

Each time the bot application starts, Botkit will register a webhook subscription. Botkit will automatically manage your bot's webhook subscriptions, but if you plan on having multiple instances of your bot application with different URLs (such as a development instance and a production instance), use the webhook_name field with a different value for each instance.

Bots in Webex are identified by their email address, and can be added to any space in any team or organization. If your bot should only be available to users within a specific organization, use the limit_to_org or limit_to_domain options. This will configure your bot to respond only to messages from members of the specific organization, or whose email addresses match one of the specified domains.

The full code for a simple Webex bot is below:

var Botkit = require('botkit');

var controller = Botkit.webexbot({
    debug: true,
    log: true,
    public_address: process.env.public_address,
    access_token: process.env.access_token,
    secret: process.env.secret
});

var bot = controller.spawn({});

controller.setupWebserver(process.env.PORT || 3000, function(err, webserver) {
    controller.createWebhookEndpoints(webserver, bot, function() {
        console.log("Webhooks set up!");
    });
});

controller.hears('hello', 'direct_message,direct_mention', function(bot, message) {
    bot.reply(message, 'Hi');
});

controller.on('direct_mention', function(bot, message) {
    bot.reply(message, 'You mentioned me and said, "' + message.text + '"');
});

controller.on('direct_message', function(bot, message) {
    bot.reply(message, 'I got your private message. You said, "' + message.text + '"');
});

When creating the Botkit controller, there are several platform-specific options available.

Argument Description
public_address required the root url of your application (https://mybot.com)
access_token required token provided by Webex for your bot
secret required secret for validating webhooks originate from Webex
webhook_name optional name for webhook configuration on Webex side. Providing a name here allows for multiple bot instances to receive the same messages. Defaults to 'Botkit Firehose'
limit_to_org optional organization id in which the bot should exist. If user from outside org sends message, it is ignored
limit_to_domain optional email domain (@howdy.ai) or array of domains [@howdy.ai, @botkit.ai] from which messages can be received
var controller = Botkit.webexbot({
    debug: true,
    log: true,
    public_address: 'https://mybot.ngrok.io',
    access_token: process.env.access_token,
    secret: 'randomstringofnumbersandcharacters12345',
    webhook_name: 'dev',
    limit_to_org: 'my_webex_org_id',
    limit_to_domain: ['@howdy.ai','@cisco.com'],
});

All events listed here should be expected, in the format resource.event - for example, rooms.created.

In addition, the following custom Botkit-specific events are fired:

Event Description
direct_message Bot has received a message as a DM
direct_mention Bot has been mentioned in a public space
self_message Bot has received a message it sent
user_space_join a user has joined a space in which the bot is present
bot_space_join the bot has joined a new space
user_space_leave a user has left a space in which the bot is present
bot_space_leave the bot has left a space

Webex supports both a text field and a markdown field for outbound messages. Read here for details on Webex's markdown support.

To specify a markdown version, add it to your message object:

bot.reply(message,{text: 'Hello', markdown: '*Hello!*'});

Files can be attached to outgoing messages in one of two ways.

Specify URL

If the file you wish to attach is already available online, simply specify the URL in the files field of the outgoing message:

bot.reply(message,{text:'Here is your file!', files:['http://myserver.com/file.pdf']});

Send Local File

If the file you wish to attach is present only on the local server, attach it to the message as a readable stream:

var fs = require('fs');
bot.reply(message,{text: 'I made this file for you.', files:[fs.createReadStream('./newfile.txt')]});

Your bot may receive messages with files attached. Attached files will appear in an array called message.data.files.

Botkit provides 2 methods for retrieving information about the file.

Parameter Description
url url of file from message.data.files
cb callback function in the form function(err, file_info)

The callback function will receive an object with fields like filename, content-type, and content-length.

controller.on('direct_message', function(bot, message) {
    bot.reply(message, 'I got your private message. You said, "' + message.text + '"');
    if (message.data.files) {
        bot.retrieveFileInfo(message.data.files[0], function(err, file_info) {
            bot.reply(message,'I also got an attached file called ' + file_info.filename);
        });
    }
});

Parameter Description
url url of file from message.data.files
cb callback function in the form function(err, file_content)

The callback function will receive the full content of the file.

controller.on('direct_message', function(bot, message) {
    bot.reply(message, 'I got your private message. You said, "' + message.text + '"');
    if (message.data.files) {
        bot.retrieveFileInfo(message.data.files[0], function(err, file_info) {
            if (file_info['content-type'] == 'text/plain') {
                bot.retrieveFile(message.data.files[0], function(err, file) {
                    bot.reply(message,'I got a text file with the following content: ' + file);
                });
            }
        });
    }
});

Webex's API provides several ways to send private messages to users - by the user's email address, or by their user id. These may be used in the case where the user's email address is unknown or unavailable, or when the bot should respond to the actor instead of the sender of a message.

For example, a bot may use these methods when handling a bot_space_join event in order to send a message to the user who invited the bot (the actor) instead of the bot itself (the sender).

NOTE: Core functions like bot.startPrivateConversation() work as expected, and will create a direct message thread with the sender of the incoming_message.

Parameter Description
personId the personId of the user to whom the bot should send a message
cb callback function in the form function(err, file_content)

Use this function to send a direct message to a user by their personId, which can be found in message and event payloads at the following location:

var personId = message.original_message.actorId;

Parameter Description
incoming_message a message or event that has an actorId defined in message.original_message.actorId
cb callback function in the form function(err, file_content)
controller.on('bot_space_join', function(bot, message) {
  bot.startPrivateConversationWithActor(message, function(err, convo) {
    convo.say('The bot you invited has joined the channel.');
  });
});

Back in April 2018, Cisco announced a rebrand from Cisco Spark to Webex. In May 2018, starting with version 0.6.17, Botkit reflected this rebrand by updated 'Spark' mentions from the framework API.

For backward compatibility purposes, several references are now marked as deprecated, but still supported (except for Typescript code). Please migrate your code if your find references to:

Breaking changes

Is something missing or out of date?

This file is managed on Github. click here to view the source, and send us a pull request with your improvements!