Messaging Platform SDK Examples

The following examples showcase how the Messaging Platform SDK can be used to establish a connection and conversations with the Conversational Cloud. The examples are divided in Brand and Consumer. Brand connections allow you to create authenticated connections with your account as an agent. These connections can be used to automate agent actions like transferring a conversation or accepting a ring.

On the other hand, consumer connections allow unauthenticated connections for consumer actions. For example, creating a conversation for a skill and sending messages. They are specific for one consumer and one conversation. Both connection types require configuration, which you need to provide. Please have a look at the corresponding sections. The example code is also available on npm and will be pulled when you install the package.

Table of Contents

Running

Once you copied your example to a file and set up the configuration like explained in the corresponding sections, run the code by calling node <filename.js> where <filename.js> refers to the file of your example. For example, you copied the basic example to basic.js, then your directory should look similar to this:

.
├── basic.js
└── config.json

Run basic.js by calling node basic.js. Note that, for some brand examples, a consumer example should also be run, in order to see conversational events.

Brand Examples

The following examples establish an authenticated brand connection. Before running, make sure that you have set up your config.json. For all brand examples, we assume that there is only one agent/bot online. Otherwise, your bot user might not receive rings. To run a brand example, copy the example to a separate file and add the config.json in the same directory. The format looks as follows:

{
  "accountId": "",
  "authData": {
    "username": "",
    "appKey": "",
    "secret": "",
    "accessToken": "",
    "accessTokenSecret": ""
  },
  "appId": ""
}

The parameters are the configurations for your bot user, your account id and the app id. The app id must contain at least one alphanumeric character, a -, . or _. For example, example-test_123 is a valid id while example test 123 is not. For the skill transfer and agent transfer examples, you need an additional file called specific-skill-config.json. It has the same format and contains information about the target agent. If you run any of those tests, make sure to create a second bot user on your account.

Accept any waiting ring

/**
 * This example uses the SDK to create a brand connection, register the agent as online and accept any ring in waiting state.
 * Then it publishes a welcome message.
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // Please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.BRAND,
    authData: config.authData
});

// Define ring callback *before* opening the connection, to ensure no lost events
connection.on('ring', async ring => {
    console.log('ring?');
    if (ring.ringState !== lpm.RingState.WAITING) {
        console.log(`Ring is already in state ${ring.ringState}, ignoring`);
        return;
    }

    await ring.accept();
    console.log('Ring accepted!');
});

connection.on('conversation', async conversation => {
    console.log('conversation received');
    // Emit message only when an assigned agent is added, which in our basic example emulates the bot itself
    conversation.on('participant-added', async participant => {
        if (participant.participant.role === lpm.ParticipantRole.ASSIGNED_AGENT) {
            await conversation.sendMessage('I accepted the ring, how may I help you?');
        }
    })
});

(async() => {
    console.log('Connecting brand bot...');
    // Open the connection
    await connection.open();
    console.log('Brand bot connected!');

    // Register to be able to accept rings
    await connection.createRoutingTaskSubscription();

    await connection.setAgentState({ agentState: lpm.AgentState.ONLINE });
})();

Make sure to run a consumer example which creates a conversation. In this way, you will be able to see the message I accepted the ring, how may I help you? from the bot user.

Close all open conversations

/**
 * This example uses the SDK to create a brand connection,
 * join all open conversations and close them.
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // Please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.BRAND,
    authData: config.authData
});

connection.on('conversation', async conversation => {
    try {
        await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
        console.log(`Joined conversation ${conversation.conversationId}`);
    } catch (error) {
        console.log(`Could not join conversation ${conversation.conversationId} due to error - ${error.message}. Will still try to close in case it's already joined.`);
    }

    try {
        await conversation.close();
        console.log(`Closed conversation ${conversation.conversationId}`);
    } catch (error) {
        console.log(`Could not close conversation ${conversation.conversationId} due to error - ${error.message}`);
    }

});

(async() => {
    console.log('Connecting brand bot...');
    // Open the connection
    await connection.open();
    console.log('Brand bot connected!');
})();

Upload file

/**
 * This example uses the SDK to create a brand connection,
 * join all open conversations and send a file upon receiving a specific message.
 *
 * NOTE: the account needs `messaging.file.sharing.enabled` site setting enabled in order to share files.
 */


const lpm = require('lp-messaging-sdk');
const fs = require('fs');
const path = require('path');

const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // Please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.BRAND,
    authData: config.authData
});

connection.on('conversation', async conversation => {
    try {
        await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
        console.log(`Joined conversation ${conversation.conversationId}`);

        conversation.on('message', async (message) => {
            if (message.body === 'upload') {
                const file = fs.readFileSync(path.resolve(__dirname, 'logo.jpg'));
                await conversation.sendMessage("sending file");
                await conversation.uploadFile(file.buffer, "upload")
                await conversation.sendMessage("done sending file");
            }
        });
    } catch (error) {
        console.log(`Could not join conversation ${conversation.conversationId} due to error - ${error.message}.`);
    }
});

(async() => {
    console.log('Connecting brand bot...');
    // Open the connection
    await connection.open();
    console.log('Brand bot connected!');
})();

Get last consumer message

/**
 * This example creates a connection, accepts a ring, awaits that the conversation to be loaded
 * and gets the last consumer message if any.
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // Please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.BRAND,
    authData: config.authData
});

// process the rings as they arrive
connection.on('ring', async ring => {

    // ignore old rings
    if (ring.ringState !== lpm.RingState.WAITING) return;

    // accept the ring
    await ring.accept();

    // await conversation or null if waiting times out.
    const conversation = await ring.conversation();

    if (conversation) {
        const latestConsumerMessage = conversation.getLatestConsumerMessage();
        if (latestConsumerMessage && latestConsumerMessage.body) {
            console.log(`Last consumer message is: "${latestConsumerMessage.body}"`);
            return;
        }

        // If consumer messages has not yet arrived when the ring is accepted, subscribe to all subsequent messages
        // for the conversation and log it whenever it arrives
        conversation.on('message', (message) => {
            const latestConsumerMessage = message.conversation.getLatestConsumerMessage();
            if (!latestConsumerMessage || !latestConsumerMessage.body) {
                console.log(`Message that we have received is not a consumer message for this conversation with id: ${ring.conversationId}`);
            } else {
                console.log(`This is the latestConsumerMessage: ${latestConsumerMessage.body} for conversation: ${ring.conversationId}`);
            }
        });
    }
});

(async() => {
    console.log('Connecting brand bot...');
    // Open the connection
    await connection.open();
    console.log('Brand bot connected!');

    // Register to be able to accept rings
    await connection.createRoutingTaskSubscription();

    await connection.setAgentState({ agentState: lpm.AgentState.ONLINE });
})();

React on different messages

/**
 * This example uses the SDK to create a brand connection,
 * join all open conversations and react to each message, based on its content
 *
 * - if it's #time, respond with current time
 * - if it's #close, close the conversation
 * - if it's something else, repeat what the consumer said
 */


const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // Please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.BRAND,
    authData: config.authData
});

connection.on('conversation', async conversation => {
    try {
        await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
        console.log(`Joined conversation ${conversation.conversationId}`);

        conversation.on('message', async (message) => {
            if (message.participant.role !== lpm.ParticipantRole.CONSUMER) {
                console.log(`Skipping non-consumer (${message.participant.role}) message!`);
                return;
            }
            if (message.body === '#time') {
                await conversation.sendMessage(`Time now is: ${new Date().toISOString()}`);
            } else if (message.body === '#close') {
                await conversation.close();
            } else {
                await conversation.sendMessage(`You said: "${message.body}"`);
            }
        });
    } catch (error) {
        console.log(`Could not join conversation ${conversation.conversationId} due to error - ${error.message}.`);
    }
});

(async() => {
    console.log('Connecting brand bot...');
    // Open the connection
    await connection.open();
    console.log('Brand bot connected!');
})();

Replay all messages

/**
 * This example uses the SDK to create a brand connection,
 * join a conversation and if message contains #replay, lists all messages, based on the exact string:
 *
 * - #replay-all - replays all messages in the order they arrived
 * - #replay-reverse - replays all messages in reverse order
 * - #replay-system - replays only the messages sent by controller or brand-bot, in the order they arrived
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // Please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.BRAND,
    authData: config.authData
});

connection.on('conversation', async conversation => {
    try {
        await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
        console.log(`Joined conversation ${conversation.conversationId}`);

        conversation.on('message', async (message) => {
            if (message.body.includes('#replay-')) {
                const messagesInDescendingOrder = await conversation.queryMessages();
                switch (message.body) {
                    case '#replay-reverse': {
                        const messageBodies = messagesInDescendingOrder.map((msg) => msg.body);
                        await conversation.sendMessage(`Here are all messages in reverse order:\n-${messageBodies.join('\n-')}`);
                    }break;
                    case '#replay-all': {
                        const messagesInAscendingOrder = messagesInDescendingOrder.map((msg) => msg.body).reverse();
                        await conversation.sendMessage(`Here are all messages in normal order:\n-${messagesInAscendingOrder.join('\n-')}`);
                    }break;
                    case '#replay-system': {
                        const systemMessages = messagesInDescendingOrder
                            .filter((msg) => [lpm.ParticipantRole.CONTROLLER, lpm.ParticipantRole.BRAND_BOT].includes(msg.participant.role))
                            .map((msg) => msg.body)
                            .reverse();
                        await conversation.sendMessage(`Here are the system messages only:\n-${systemMessages.join('\n-')}`);
                    }
                }
            }
        });
    } catch (error) {
        console.log(`Could not join conversation ${conversation.conversationId} due to error - ${error.message}.`);
    }
});

(async() => {
    console.log('Connecting brand bot...');
    // Open the connection
    await connection.open();
    console.log('Brand bot connected!');
})();

Transfer to agent

/**
 * This example joins a conversation and, upon a certain message, transfers to specific agent.
 *
 * NOTE: You'll need the `Messaging.Transfer_To_Agent` AC Feature enabled to be enabled to be able to transfer to specific agent.
 */

const lpm = require('lp-messaging-sdk');
const originalBrandConnectionConfig = require('./config.json');

const regularBrandConnection = lpm.createConnection({
    appId: originalBrandConnectionConfig.appId, // Please change to something unique to your application
    accountId: originalBrandConnectionConfig.accountId,
    userType: lpm.UserType.BRAND,
    authData: originalBrandConnectionConfig.authData
});

//NOTE: make sure this is the same agent id as the one, described in specificSkillBrandConnectionConfig
const desiredAgentId = '4615909832';
const specificSkillBrandConnectionConfig = require('./specific-skill-config.json');

const specificSkillBrandConnection = lpm.createConnection({
    appId: specificSkillBrandConnectionConfig.appId, // Please change to something unique to your application
    accountId: specificSkillBrandConnectionConfig.accountId,
    userType: lpm.UserType.BRAND,
    authData: specificSkillBrandConnectionConfig.authData
});

regularBrandConnection.on('conversation', async conversation => {
    try {
        await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
        console.log(`Regular bot joined conversation ${conversation.conversationId}`);

        conversation.on('message', async message => {
            if (message.body === '#transfer') {
                // NOTE: when transferring to a specific agent, specify the whole agent id, i.e. `accountId.agentId`,
                // instead of just `agentId`.
                conversation.transfer({agentId: `${originalBrandConnectionConfig.accountId}.${desiredAgentId}`});
            }
        });
    } catch (error) {
        console.log(`Could not join conversation ${conversation.conversationId} due to error - ${error.message}.`);
    }
});

specificSkillBrandConnection.on('conversation', async conversation => {
    conversation.on('transfer-agent', async participant => {
        // Listen to events that transfer to specific agent and check only if all three criterias are fulfulled:
        // - id is the id of the agent
        // - role is assigned_agent
        // - state of the participant is still SUGGESTED (not ACTIVE, which would mean that the agent already has joined)
        if (participant.agentId === `${specificSkillBrandConnectionConfig.accountId}.${desiredAgentId}`
            && participant.role === lpm.ParticipantRole.ASSIGNED_AGENT
            && participant.state === lpm.ParticipantState.SUGGESTED) {
            await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
            console.log(`Specific agent bot joined conversation ${conversation.conversationId}`);
            await conversation.sendMessage('Hi, I heard you are looking for me?');
        } else {
            console.log(`ID: ${participant.agentId}; role: ${participant.role}; state: ${participant.state}`);
        }
    });
});

(async() => {
    console.log('Connecting brand bots...');

    // Open the connections
    await regularBrandConnection.open();
    console.log('Regular brand bot connected!');

    await specificSkillBrandConnection.open();
    console.log('Specific agent brand bot connected!');
})();

Transfer to skill

/**
 * This example joins a conversation and, upon a certain message, transfers to specific skill.
 */

const lpm = require('lp-messaging-sdk');
const originalBrandConnectionConfig = require('./config.json');

const regularBrandConnection = lpm.createConnection({
    appId: originalBrandConnectionConfig.appId, // Please change to something unique to your application
    accountId: originalBrandConnectionConfig.accountId,
    userType: lpm.UserType.BRAND,
    authData: originalBrandConnectionConfig.authData
});

//NOTE: make sure this skill id is assigned to the brand, using the specificSkillBrandConnectionConfig
const desiredSkillId = '4615909532';
const specificSkillBrandConnectionConfig = require('./specific-skill-config.json');

const specificSkillBrandConnection = lpm.createConnection({
    appId: specificSkillBrandConnectionConfig.appId, // Please change to something unique to your application
    accountId: specificSkillBrandConnectionConfig.accountId,
    userType: lpm.UserType.BRAND,
    authData: specificSkillBrandConnectionConfig.authData
});

regularBrandConnection.on('conversation', async conversation => {
    try {
        await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
        console.log(`Regular bot joined conversation ${conversation.conversationId}`);

        conversation.on('message', async message => {
            if (message.body === '#transfer') {
                conversation.transfer({skillId: desiredSkillId});
            }
        });
    } catch (error) {
        console.log(`Could not join conversation ${conversation.conversationId} due to error - ${error.message}.`);
    }
});

specificSkillBrandConnection.on('conversation', async conversation => {
    // Listen to events that transfer to skill and join if it's changing to the desired skill id
    conversation.on('transfer-skill', async (ev) => {
        if (ev.skillId === desiredSkillId) {
            await conversation.join(lpm.ParticipantRole.ASSIGNED_AGENT);
            console.log(`Specific skill bot joined conversation ${conversation.conversationId}`);
            await conversation.sendMessage('I am your new assistant!');
        }
    });
});

(async() => {
    console.log('Connecting brand bots...');

    // Open the connections
    await regularBrandConnection.open();
    console.log('Regular brand bot connected!');

    await specificSkillBrandConnection.open();
    console.log('Specific skill brand bot connected!');
})();

Consumer Examples

The configuration for consumer examples do not contain authentication data. Additionally, they contain client properties and a skill. To run a consumer example, copy the example to a separate file and add the config.json in the same directory. The format looks as follows:

{
  "accountId": "",
  "clientProperties": {
    "deviceFamily": "",
    "deviceManufacturer": "",
    "deviceModel": "",
    "osName": "",
    "osVersion": "",
    "ipAddress": "",
    "browser": "",
    "browserVersion": "",
    "timeZone": "",
    "features": ["AUTO_MESSAGES", "PHOTO_SHARING"]
  },
  "appId": "",
  "skillId": "4725444232"
}

The app id must contain at least one alphanumeric character, a -, . or _. For example, example-test_123 is a valid id while example test 123 is not. Client properties contain free-form values for customer details. You can enter anything that you want. Note that, PHOTO_SHARING and AUTO_MESSAGES features are required for the examples to work, so they are already filled.

Basic conversation example

/**
 * This is the most basic example of a consumer connection, using all default values,
 * sends a message and closes the conversation after 5 seconds
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // TODO: please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.CONSUMER
});

// log any internal errors (auth errors, etc)
connection.on('error', err => {
    console.error(err);
});

const waitSeconds = (time) => {
    return new Promise((resolve) => setTimeout(resolve, time * 1000));
};

(async() => {
    console.log('Connecting consumer...');

    // connect & open conversation
    await connection.open();

    console.log('Consumer connected!');

    // create conversation
    const conversation = await connection.createConversation();

    console.log('Conversation created!');

    // send a message
    await conversation.sendMessage('Example message');

    await waitSeconds(5);

    // close the main dialog
    await conversation.close();

    // close the connection
    await connection.close();

    console.log('Conversation and connection closed!');
})();

Close on Message

/**
 * This example creates a connection and a conversation and subscribes to messages.
 * Upon receiving a message with exact content "42" it thanks the agent and closes the conversation.
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // TODO: please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.CONSUMER
});

// log any internal errors (auth errors, etc)
connection.on('error', err => {
    console.error(err);
});

const waitSeconds = (time) => {
    return new Promise((resolve) => setTimeout(resolve, time * 1000));
};

(async() => {
    console.log('Connecting consumer...');

    // connect & open conversation
    await connection.open();

    console.log('Consumer connected!');

    // create conversation
    const conversation = await connection.createConversation();

    conversation.on('message', async message => {
        if (message.body === '42') {
            await conversation.sendMessage('Thank you for answering everything!');
            await conversation.close();
            await connection.close();
            console.log('Conversation and connection closed!');
        }
    });

    console.log('Conversation created!');

    await waitSeconds(2);

    // send a message
    await conversation.sendMessage('Tell me everything');
})();

Continue consumer session

/**
 * This example creates a connection, gets its token, creates a conversation and sends a message in it,
 * then closes the connection, reopens a new connection with the same token and sends another message in the same conversation
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection1 = lpm.createConnection({
    appId: config.appId, // TODO: please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.CONSUMER
});

const waitSeconds = (time) => {
    return new Promise((resolve) => setTimeout(resolve, time * 1000));
};

(async() => {
    console.log('Connecting consumer...');

    // connect & open conversation
    await connection1.open();

    // get and store the token
    const token = await connection1.getToken();

    // create conversation
    const conversation = await connection1.createConversation();
    const conversationId = conversation.conversationId;

    console.log(`Conversation #${conversationId} created!`);

    // send a message
    await conversation.sendMessage('Example message #1 using the first connection');

    await waitSeconds(1);

    // close the first connection
    await connection1.close();

    console.log('First connection closed!');

    // open new connection with the same token
    const connection2 = lpm.createConnection({
        userType: lpm.UserType.CONSUMER,
        appId: config.appId, // TODO: please change to something unique to your application
        accountId: config.accountId,
        token,
        waitForReady: true
    });

    await connection2.open();

    console.log('Second connection created!');

    // Find the conversation based on the conversation id, in case there are many conversations in the connection
    const conversation2 = Array.from(connection2._conversations.values()).find((conversation) => conversation.conversationId === conversationId);
    await conversation2.sendMessage('Example message #2 after reopening connection with the same token');

    // close the second conversation
    await conversation2.close();

    // close the second connection
    await connection2.close();

    console.log('Second conversation and connection closed!');
})();

Conversation for skill

/**
 * This example creates a conversation for a specific skill only, and sends a message to it.
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

const connection = lpm.createConnection({
    appId: config.appId, // TODO: please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.CONSUMER
});


// log any internal errors (auth errors, etc)
connection.on('error', err => {
    console.error(err);
});

(async() => {
    console.log('Connecting consumer...');

    // connect & open conversation
    await connection.open();

    console.log('Consumer connected!');

    // create conversation
    const conversation = await connection.createConversation({
        skillId: config.skillId
    });

    console.log('Conversation created!');

    // send a message
    await conversation.sendMessage('Example message');
})();

Conversation for language

/**
 * This example creates a connection and a conversation and subscribes to messages in a specific language.
 */

const lpm = require('lp-messaging-sdk');
const config = require('./config.json');

// Make some Fake clientProperties
const clientProperties = lpm.createClientProperties(config.clientProperties);

const connection = lpm.createConnection({
    appId: config.appId, // TODO: please change to something unique to your application
    accountId: config.accountId,
    userType: lpm.UserType.CONSUMER,
    defaultSubscriptionQuery: {
        stage: ["OPEN", "CLOSE"],
    },
    clientProperties
});

const context = {
    type: lpm.ConversationContextType.SHARK,
    lang: 'it-IT', //specify locale code for the language you want the conversation to be created
    visitorId: ''
};

// log any internal errors (auth errors, etc)
connection.on('error', err => {
    console.error(err);
});

const waitSeconds = (time) => {
    return new Promise((resolve) => setTimeout(resolve, time * 1000));
};

(async() => {
    console.log('Connecting consumer...');

    // connect & open conversation
    await connection.open();

    console.log('Consumer connected!');

    // create conversation
    const conversation = await connection.createConversation({
        context
    });

    conversation.on('message', async message => {
        if (message.participant.role !== lpm.ParticipantRole.CONSUMER) {
            console.log(`Message received - ${message.body}`);
        }
    });

    console.log('Conversation created!');

    await waitSeconds(2);

    // send a message
    await conversation.sendMessage('Tell me everything');
})();