Overview

The Engagement API utilizes WebSockets to create a bidirectional communication channel between the user's browser and the server. WebSockets enable sending messages to the server and receiving event-driven responses without the need for polling the server for a reply.

Steps

  1. Create a user: Before establishing a WebSocket connection, make sure to create a user using the appropriate API method.
  2. Establish a WebSocket connection: After the user has been created, establish a WebSocket connection as demonstrated in the example below.
  3. Join the chat channel: Use the join function of the Elixir/Channels library (e.g., Phoenix Channels JavaScript client) to join the chat channel chat:{CHAT_ID}. This step is necessary to receive messages from Pypestream and to send and receive heartbeat protocol messages, which maintain the connection. Join the chat channel before starting the engagement to ensure receipt of initial messages from the microapp.
  4. Wait for the chat:ready event: After sending the request to start the engagement, wait for the chat:ready event to be received via WebSocket. This event signifies that it is safe to proceed with using other endpoints, such as sending messages. If a request is sent before receiving the chat:ready event, the API will return a 428 error.
  5. Receive responses: When a response arrives, the incoming:msg event will be received through the WebSocket, allowing further processing or interaction.

URLs

EnvironmentURL
Sandboxwss://engagement-api-sandbox.pypestream.com/socket/websocket
Livewss://engagement-api.pypestream.com/socket/websocket

Connection Variables

To establish a sample WebSocket connection, you will need the following variables:

VariableDescription
tokenThe access token, which is returned in the Create User request.
Using the Phoenix Channels JavaScript client, a WebSocket connection can be established as shown in the example below. Replace {URL} with the WebSocket URL and {MY_TOKEN} with the token retrieved from the Create User request:

A WebSocket connection using the Phoenix Channels JavaScript client would look like this, where MY_TOKEN is the token retrieved through the Create User:

let socket = new Socket("wss://{URL}/socket/websocket", {params: {token: {MY_TOKEN}}})
socket.connect()

Joining a Channel

To join a channel, use the .join() function. Make sure to include the topic (see the definition of "topic" below) you're connecting to and the authorization information for that channel.

📘

What is a topic?

A topic represents a chat. It is always a string in the format chat:{ChatID}, such as "chat:42c6a240-1bf9-4164-8d75-9a608f1117c9". Before sending or receiving any messages, join the "topic" using the join function from the library you're using.

After connecting to the WebSocket with the Phoenix Channels JavaScript client, establish a connection on the channel variable. This step would appear as follows:

let channel = socket.channel("chat:{ChatID}", {user_id: "{UserID}", access_token: "{AccessToken}"})
channel.join()
  .receive("ok", ({messages}) => {YourSuccessFunction} )
  .receive("error", ({reason}) => {YourFailureFunction} )
  .receive("timeout", () => {YourTimeoutFunction})

Replace the {ChatID}, {UserID} and {AccessToken} with their respective value.

Events

The following messages can be sent through the WebSocket connection:

EventSourceDescription
chat:startClientStarts the engagement. After sending this event, the client must wait for the chat:ready event that will indicate that everything is ready to receive messages.
chat:readyPypestreamInforms the Client that the chat is ready to receive send_message requests, if a message is received before getting this event it will be rejected with a 428 status.
new:pingClientResets the connection counter timeout. This is used to keep the connection from timing out and disconnecting. A ping message should be sent every 20 seconds to prevent disconnection.
new:pongPypestreamThis is sent from Pypestream back to the client as a response to the ping message.
msg:sendClientA message transmitted from the end-user to the microapp.
incoming:msgPypestreamA message transmitted from the microapp to the end-user.
incoming:noticePypestreamEnable a microapp to send a notice to the end-user of the chat.
chat:endClientTerminates the chat established between the end-user and the microapp.
chat:snapshotClientA request for a snapchat of the engagement as it currently stands.
chat:snapshot_responsePypestreamAn object with all the relevant information of the engagement at the moment the request was done.

chat:start

The chat:start message payload has the following fields:

VariableTypeRequired (Y/N)Description
app_idstringYThe ID of the interface this engagement is associated with.
consumerstringYThe ID of the consumer interacting in this engagement.
gatewaystringYGateway type. Possible value(s): pypestream_widget
pype_idstringYThe ID of the internal Pypestream environment to which the microapp is deployed.
stream_idstringYThe ID of the internal "stream" that the microapp is connected to within the Pypestream environment. Multiple streams are allowed to live within one singular environment ("pype").
user_idstringYThe ID of the user interacting in this engagement.
versionstringYInternal message version. Possible value(s): 1.
access_tokenstringYThe access token received in the Create User response.

chat:ready

The chat:ready message payload has the following fields:

VariableTypeRequired (Y/N)Description
chat_IDstringYThe engagement ID.

new:ping

The new:ping message payload has the following fields:

VariableTypeRequired (Y/N)Description
seqnumberYThe sequential identifier.
user_idstringYID of the user submitting the message.
access_tokenstringYThe access token received in the Create User response.

new:pong

The new:pong message payload has the following fields:

VariableTypeRequired (Y/N)Description
seqnumberYThe sequential identifier.
user_idstringYID of the user submitting the message.

msg:send

The msg:send message payload has the following variables:

VariableTypeRequired (Y/N)Description
app_objectstringNAn object for the embedded object data. Passes through on platform side.
campaign_idstringNThe ID of the campaign this message originated from.
client_msg_idstringNClient generated unique message ID.
correlation_idstringNA unique ID set by the client which can be used to correlate the responding acknowledgement of the request.
filestringNA URL to a file to embed in the message.
file_statusstringNIndicates if the file is available for downloading from the URL. Possible value(s): uploading, ready, failed
fromstringYID of the user submitting the message.
from_sidestringYIndicates the source of the message. Possible value(s): anonymous_consumer
gatewaystringYGateway type. Possible value(s): pypestream_widget
msgstringNThe contents of the message being submitted.
msg_typestringYMessage type. We support text and embed. If it is text, then the msg field is required, but if it is embed, then the msg will be null, and the app_object and secure_app_object fields are required.
persist_to_historybooleanNFlags whether this message should be written to the persistent conversational history.
requeuedintegerNSystem use only.
secure_app_objectbooleanNFlags whether this is a secure message and, thus, should not be persisted to the conversation history.
user_idstringYID of the user submitting the message.
versionintegerYInternal message version. Possible value(s): 1.
access_tokenstringYThe access token received in the Create User response.

incoming:msg

The incoming:msg message payload has the following variables:

VariableTypeRequired (Y/N)Description
chat_idstringYID of the conversation you're receiving the message from.
msg_actionstringNAction of the message. Possible value(s): new, update
fromstringYID of the user submitting the message.
from_sidestringYIndicates the source of the message. Possible value(s): company, agent, manager, bot, system, anonymous_consumer
msg_typestringYThe type of message. Possible value(s): text, embed
seq_numintegerNMessage sequence number from internal server.
timestampintegerNDatetime in Unixtime format.
msgstringYThe contents of the message being submitted.
client_msg_idstringNClient generated unique message ID.
filestringNA URL to a file to embed in the message.
file_statusstringNIndicates if the file is available for downloading from the URL. Possible value(s): uploading, ready, failed
app_objectstringNAn object for the embedded object data.
orig_app_objectstringNThe original embedded object data if it has been changed.
secure_app_objectbooleanNFlags whether this is a secure message and, thus, should not be persisted to the conversation history.
free_textbooleanNFlags whether this is a free text message.
campaign_idstringNThe ID of the campaign this message originated from.
metadataarrayNMetadata of the message.
encryptedbooleanNFlags whether this message is encrypted.
persist_to_historybooleanNFlags whether this message should be written to the persistent conversational history.
eventsarrayNList of events.

incoming:notice

The incoming:notice message payload has the following variables:

VariableTypeRequiredDescription
detailstringYThe type of notice sent to the end-user. Possible value(s): chat
source_actionstringYPossible value(s): new or update.
originstringYPossible value(s):user, bot, system
versionstringYInternal message version. Possible value(s): 1
dataobjectYThe payload of the notice sent.

chat:end

The chat:end message payload has the following variables:

VariableTypeRequired (Y/N)Description
ended_bystringYThe agent who ended the chat.
pype_idstringYPype ID to which this chat belongs.
sourcestringYThe source the chat conversation was ended by. Possible value(s): agent, consumer
user_idstringYID of the user submitting the message.
versionintegerYInternal message version. Possible value(s): 1
access_tokenstringYThe access token received in the Create User response.

chat:snapshot

The chat:snapshot message payload has the following variables:

VariableTypeRequiredDescription
fromstringYID of user who requested the snapshot.
access_tokenstringYThe access token received in the Create User response.

chat:snapshot_response

The chat:snapshot_response message payload has the following variables:

VariableTypeRequired (Y/N)Description
idstringYThe ID of the engagement.
botstringNThe microapp ID.
bot_namestringNName of the microapp used.
bot_enabledbooleanNFlag if the engagement has a microapp enabled.
bot_msg_countintegerNThe number of messages sent by the microapp
bot_started_countintegerNThe number of microapps used.
with_end_botbooleanNIndicates if the engagement contains a survey microapp.
target_bot_nodestringNLast node of the microapp reached.
app_idstringNThe ID of the interface this engagement is associated with.
pype_idstringNThe ID of the internal Pypestream environment to which the microapp is deployed.
pype_namestringNThe name of the internal Pypestream environment to which the microapp is deployed.
stream_idstringNThe ID of the internal "stream" that the microapp is connected to within the Pypestream environment. Multiple streams are allowed to live within one singular environment ("pype").
stream_namestringNThe name of the internal "stream" that the microapp is connected to within the Pypestream environment.
consumerstringNThe ID of the consumer.
consumer_namestringNThe name of the consumer.
consumer_typestringNType of consumer. Possible value(s): anonymous, server
consumer_msg_countstringNThe number of messages sent by the consumer.
originator_user_idstringNThe ID of the user who originated the engagement.
originator_namestringNThe name of the user who originated the engagement.
originating_sidestringNWhich side started the chat. Possible value(s): consumer, bot, agent
agentstringNID of the agent assigned to the engagement.
agent_namestringNThe name of the agent assigned to the engagement.
agent_routingstringNContact Center Service. Possible values(s): external_agent
agent_is_assignedbooleanNIndicates if an agent is assigned to the engagement.
agent_msg_countintegerNThe number of messages sent by the agent.
agent_assign_tsintegerNUnixtime of the agent assignment time.
agent_response_tsintegerNUnixtime of the last agent response.
participant_changedbooleanNIndicates if the engagement participant has changed.
participantsarrayNList of engagement participants.
participant_historyarrayNList of engagement participant changes.
start_tsintegerNUnixtime for start of the engagement.
end_tsintegerNUnixtime for end of the engagement.
last_updatedstringN
ended_bystringNID of the user that ended the engagement.
end_tagsstringNTags/codes assigned to the engagement by the agent after it is completed.
end_commentstringNComments assigned to the engagement by the agent after it is completed.
gatewaystringNGateway type. Possible value(s): pypestream_widget
historyarrayNList of all engagement messages.
delivery_receiptsarrayNList of delivery receipts that consumer received in the engagement.
gateway_metadataobjectNMetadata of the engagement.
user_read_countsarrayNList of consumer reads.
read_receiptsarrayNList of read receipts from consumer received in the engagement.
versionstringNchat:snapshot_response version
seq_numintegerNSequential number of the last message received or sent.
statusstringNStatus of the engagement. Possible value(s): new, active, active_with_bot, active_with_agent, ended
access_tokenstringNThe access token received in the Create User response.
encryptedbooleanNIndicates if the engagement is encrypted.
persist_bot_historybooleanNIndicates if the engagement should save the microapp conversational history.
initial_msgstringNInitial message of engagement.

Example

Here is an example of how to push events to the channel and listen for events. In the following example, the channel is set up to listen for the "new_msg" event and send the "new_msg" event back to the Websocket.

Please see the Phoenix Channels JavaScript client documentation

let channel = socket.channel("room:123", {token: roomToken})
channel.on("new_msg", msg => console.log("Got message", msg) )
$input.onEnter( e => {
  channel.push("new_msg", {body: e.target.val}, 10000)
    .receive("ok", (msg) => console.log("created message", msg) )
    .receive("error", (reasons) => console.log("create failed", reasons) )
    .receive("timeout", () => console.log("Networking issue...") )
})

channel.join()
  .receive("ok", ({messages}) => console.log("catching up", messages) )
  .receive("error", ({reason}) => console.log("failed join", reason) )
  .receive("timeout", () => console.log("Networking issue. Still waiting..."))

Status Codes

The following are the possible response codes based on the requests:

Status CodeReasonDescription
HTTP 400Missing ParameterA requested parameter is missing from the connection request (e.g., token or user_id).
HTTP 403Invalid TokenThe access token is invalid. Please see Create User for more details.
WebSocket 1007Invalid MessageThe message is improperly formatted.
WebSocket 1000TimeoutThe WebSocket session has timed out.