Note: Cisco Spark is now Cisco Webex Teams. Expects changes to this document as the transition continues, but for now you may use them interchangably

Table of Contents

  1. Install Botkit on your computer

  2. Create a Botkit powered Node app:

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

Botkit receives messages from Webex Teams 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 Teams, get an access token here. In addition to the access token, Webex Teams 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 Teams 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 Teams bot is below:

var Botkit = require('./lib/Botkit.js');

var controller = Botkit.sparkbot({
    debug: true,
    log: true,
    public_address: process.env.public_address,
    ciscospark_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("SPARK: 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 + '"');
});

To connect Botkit to Webex Teams, use the Spark constructor method, Botkit.sparkbot(). This will create a Botkit controller with all core features as well as some additional methods.

Argument Description
studio_token String
debug Boolean
public_address required the root url of your application (https://mybot.com)
ciscospark_access_token required token provided by Webex Teams for your bot
secret required secret for validating webhooks originate from Webex Teams
webhook_name optional name for webhook configuration on Webex Teams 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.sparkbot({
    debug: true,
    log: true,
    public_address: 'https://mybot.ngrok.io',
    ciscospark_access_token: process.env.access_token,
    secret: 'randomstringofnumbersandcharacters12345',
    webhook_name: 'dev',
    limit_to_org: 'my_spark_org_id',
    limit_to_domain: ['@howdy.ai','@cisco.com'],
});

In addition to the core events that Botkit fires, this connector also fires some platform specific events.

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

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

Event Description
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 Teams supports both a text field and a markdown field for outbound messages. Read here for details on Webex Teams'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.original_message.files.

Botkit provides 2 methods for retrieving information about the file.

Parameter Description
url url of file from message.original_message.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.original_message.files) {
        bot.retrieveFileInfo(message.original_message.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.original_message.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.original_message.files) {
        bot.retrieveFileInfo(message.original_message.files[0], function(err, file_info) {
            if (file_info['content-type'] == 'text/plain') {
                bot.retrieveFile(message.original_message.files[0], function(err, file) {
                    bot.reply(message,'I got a text file with the following content: ' + file);
                });
            }
        });
    }
});

Webex Teams'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.');
  });
});

Cisco hosts a Botkit Developer team over on their public webex team channel. You can pop in here if you have questions about developing for Webex teams.

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!