ECE Messaging API & Webhook Server
Reference
Setup Steps
- Add an 'External App' 'Authentication'
- Partition → Integration → External Apps → Authentication
- Add → Name, Description, Type (General), Authentication Type (Basic or OAuth 2.0)
- select 'Configuration' tab
- For Basic Auth - just enter username / password.
- For Oauth2.0 - enter the necessary fields.
- Note - this Auth config is assigned to the 'Application' (next step) - and sets the Authorization header - which would then be verified by the webhook server to confirm its from an authenticated source. It is not used to authenticate with ECE.
- Register a new Application
- Partition → Integration → External Apps → Register Applications
- In General Tab, enter 'Name', Application Type → Chat
- In Callback URL enter
- the URL of your webhook server (this comes from ECE Data Server), e.g. https://mywebhookserver/webhook1
- callback format (JSON or XML)
- Callback error notification email
- Authentication (Select from dropdown - the application auth you created in the above step)
- After Saving - Copy and save the Client Key and Client Secret
- This is used by the API to login to ECE to retrieve the Bearer token - see example below.
- The API uses Basic Auth and the client key is the username, and client secret is the password.
- Add Messaging Adapter
- Select the Relevant Department (where the entry points are).
- Select Apps → Messaging Adaptors → 'New'
- Select New
- Enter Name, Description, the Registered App (created above)and assign the Entry Points to be allowed to be used with this 'messaging adaptor'.
- Note custom messages can also be uploaded here
High Level Messaging Steps
- Login and get bearer token using basic auth of client key and secret (this lasts 24 hours)
- Get the relevant Entrypoint and find its LastModifed Date
- Start Conversation - Conversation and Activity ID returned - store the Conversation ID!
- Set - email address of customer
- Set - Entry point ID
- Set - Entry point last modified date
- Set - Enable start / end typing to be sent to webhook server if you want it (not enabled by default)
- Retrieve in the response the Conversation ID and Activity ID
- Send Message
- Uses the Conversation ID
- Receive messages via Webhook server (all agents responses sent to webhook server) - note we can also send & receive the start and end typing notifications (if enabled when we start the conversation).
- End Conversation (HTTP PUT)
- Conversation ID is in the URL
Login
Summary
The authentication scheme used by this API. This API only supports “Basic” authentication scheme. Hence, the value must be “Basic ” followed by the base64 encoded string comprising of client key + colon + client secret. To elaborate, the value must be “Basic <base64 encoded value of <client_key>:<client_secret»”
Overview
Convert the client key and the client secret from the Registered App in ECE into Base 64. Example:
- Client Key = ABCD
- Client Secret = 01234
- ABCD:01234 → QUJDRDowMTIzNA==
i.e. this is just Basic Auth - the username is the Client Key and the Password is the Client Secret.
HTTP Method: POST Authorization: Basic [Base 64 value of client key and secret - (see above)] Content-Type: application/x-www-form-urlencoded Accept: application/json Url-encode: grant_type=client_credentials
Example:
curl --location 'https://ece-webserver.mydomain.com/system/ws/v19/clientapplications/authentication/oauth2/token' \ --header 'Authorization: Basic QUJDRDowMTIzNA==' \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials'
You should get a response with the Bearer token and when it will expire (24 hours).
Example HTTP Response
statusCode: 200 OK
{"access_token":"5a0f0bc4-dc21-44c8-a50b-b12bad7ae41e","expires_in":86400,"token_type":"Bearer"}
Get Entrypoint
We need to get the Entrypoint - to find the lastModified Date of the EntryPoint ID. Which will be returned in along with other details.
This can be cached so there is no need to check the EntryPoint ID config, before starting every conversation, but if caching you should handle the error and re-retrieve the latest lastModified data again, if you get a 409 Conflict returned when starting a conversation.
curl --location 'https://ece-webserver.mydomain.com/system/ws/v19/clientapplications/messaging/configuration?entrypoint=1001' \ --header 'Authorization: Bearer 5a0f0bc4-dc21-44c8-a50b-b12bad7ae41e' \ --header 'Accept: application/json' \
Example HTTP Response
statusCode: 200 OK
{ "entryPointConfiguration": [ { "entryPoint": { "id": 1001 }, "lastModified": { "date": "2023-06-16T10:25:13.000Z" }, "maskingConfiguration": { "patterns": { "pattern": [ { "name": "Visa Credit Card 16 Digits", "maskingCharacter": "*", "javascriptRegularExpression": "4(((\\r)?\\n){0,2}[0-9]){15}|4(((\\r)?\\n){0,2}[0-9]){3}(((\\r)?\\n){0,2}[-](((\\r)?\\n){0,2}[0-9]){4}){3}|4(((\\r)?\\n){0,2}[0-9]){3}(((((\\r)?\\n){1,2}[ ?])|([ ?]((\\r)?\\n){1,2})|([ ?]|((\\r)?\\n){1,2}))[0-9](((\\r)?\\n){0,2}[0-9]){3}){3}", "javaRegularExpression": "4(((\\r)?\\n){0,2}[0-9]){15}|4(((\\r)?\\n){0,2}[0-9]){3}(((\\r)?\\n){0,2}[-](((\\r)?\\n){0,2}[0-9]){4}){3}|4(((\\r)?\\n){0,2}[0-9]){3}(((((\\r)?\\n){1,2}[ ?])|([ ?]((\\r)?\\n){1,2})|([ ?]|((\\r)?\\n){1,2}))[0-9](((\\r)?\\n){0,2}[0-9]){3}){3}", "numOfCharsToUnmaskFromLeft": 0, "numOfCharsToUnmaskFromRight": 0, "applyLuhnAlgorithm": false }, { "name": "MasterCard Credit Cards", "maskingCharacter": "*", "javascriptRegularExpression": "5((\\r)?\\n){0,2}[1-5](((\\r)?\\n){0,2}[0-9]){14}|5((\\r)?\\n){0,2}[1-5](((\\r)?\\n){0,2}[0-9]){2}(((\\r)?\\n){0,2}[-](((\\r)?\\n){0,2}[0-9]){4}){3}|5((\\r)?\\n){0,2}[1-5](((\\r)?\\n){0,2}[0-9]){2}(((((\\r)?\\n){1,2}[ ?])|([ ?]((\\r)?\\n){1,2})|([ ?]|((\\r)?\\n){1,2}))([0-9]((\\r)?\\n){0,2}){3}[0-9]){3}", "javaRegularExpression": "5((\\r)?\\n){0,2}[1-5](((\\r)?\\n){0,2}[0-9]){14}|5((\\r)?\\n){0,2}[1-5](((\\r)?\\n){0,2}[0-9]){2}(((\\r)?\\n){0,2}[-](((\\r)?\\n){0,2}[0-9]){4}){3}|5((\\r)?\\n){0,2}[1-5](((\\r)?\\n){0,2}[0-9]){2}(((((\\r)?\\n){1,2}[ ?])|([ ?]((\\r)?\\n){1,2})|([ ?]|((\\r)?\\n){1,2}))([0-9]((\\r)?\\n){0,2}){3}[0-9]){3}", "numOfCharsToUnmaskFromLeft": 0, "numOfCharsToUnmaskFromRight": 0, "applyLuhnAlgorithm": false } ] }, "enableOffRecordMessages": false }, "attachmentPolicies": { "restrictionType": { "value": "block_specific" }, "fileExtensions": ".csv", "chatPolicy": { "isEnabled": true, "attachmentSize": 3 } } } ] }
Start Conversation
Start the Conversation with the relevant EntryPoint ID, the last modified date of the entry point ID (see get EntryPoint details above) and the email address of the customer.
Note - we can also request to enable Typing notification (which is NOT enabled by default). To do so, include the variable sendTypingNotification in the URL and setting it to yes, and the webhook server will receive notification when the agent starts and stops typing.
Note when enabled - if the agent presses a key, the a start notification will be sent (see below for examples), once they stop typing it will wait about 5 seconds before sending a stop notification.
This can then be used to show or hide a “Agent is typing…” notification
The below also gives an example of setting a custom attribute - which in this the attribute name is: “activity_test_string1” The string supports only certain characters as documented below- note an example of a character which is NOT supported is the “+” symbol.
- Lowercase a to z, Uppercase A to Z, Digit 0-9, @, Space, :, Dot (.), _, -, &, Comma (,), Open parenthesis (, Close parenthesis ), ?, #, =, Singlequote ', Double quote “, All characters above ASCII codeset 128
curl --location 'https://ece-webserver.mydomain.com/system/ws/v19/clientapplications/messaging/conversation/start?searchContactOnAttribute=email.emailAddress&sendTypingNotification=yes' \ --header 'Authorization: Bearer 5a0f0bc4-dc21-44c8-a50b-b12bad7ae41e' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header 'Accept-Language: en-US' \ --data-raw '{ "entryPointConfiguration": { "entryPoint": { "id": "1001" }, "lastModified": { "date": "2023-06-16T10:25:13.000Z" } }, "activity": { "subject":"Hello this is a summary - max of 255 characters", "customAttributes": { "customAttribute": [ { "attribName":"activity_test_string1", "attribValues":{ "attribValue":[ { "value":"Test String Value" } ] } } ] }, "payload": { "chat": { "clientInfo": { "referrerName": "TestReferrerName", "referrerUrl": "https://orourke.tv/chat/" } } }, "customer": { "type": { "value": "individual" }, "contacts": { "contact": [ { "firstName": "Charlie", "lastName": "Cheeze", "email": [ { "emailAddress": "[email protected]" } ] } ] } } } }'
Example HTTP Response
statusCode: 200 OK
Note - this response includes the conversation id - although it just calls it “id” in the response, which is included in responses in sent to the webhook server and is also used in the Send Message API.
{ "activity": { "case": { "id": 4329 }, "id": 4329 }, "id": "645ac530-7520-4daa-b95c-8e8cad6fcda7" }
Error Response Example
An example of an error response - if the Entry Point Modified Date was incorrect:
HTTP Status Code: 409
Body:
{ "code": "409-100", "developerMessage": "Last modified date provided in the request body for the following do not match : conversation.entryPointConfiguration." }
Message Responses from the Agent to the customer - (Webhook Server)
The agent will respond to the chat - and these responses will be sent to the configured webhook server. To authenticate the responses - we can use OAuth or Basic Authentication.
Below is an example of the initial response sent by the system when the agent replied back with “Hello”. Note - how the Conversation ID matches the above - which we got as a response to the Start Conversation API Request.
As you can see from the below examples - we can see if the responses sent are from the agent OR from the system. e.g. when an agent is assigned to the chat, the ECE sends a message with
- “sender”:{“type”:“system”}
- “type”:{“value”:“assigned”}
- and other relevant information (agent screen name for example).
When an agent completes the chat, ECE sends a system from
- “sender”:{“type”:“system”}
- “type”:{“value”:“complete”} etc.
When an agent sends a message to the customer, it uses
- “sender”:{“type”: “user”,”user“}
- “type”:{“value”:“text/html”},
with the content containing the message, e.g. “content”: “Hello”.
See below example for actual examples and some of the other details it also sends along with above.
{ "message": [ { "content": "You are now chatting with Banana Man", "conversation": { "id": "02945e5e-d5a5-48c6-96f6-969c1c32d125" }, "id": "7860514302", "sender": { "type": "system" }, "timeStamp": 1736780710000, "type": { "user": { "name": "eir support1", "screenName": "Banana Man" }, "value": "assigned" } }, { "content": "Hello", "conversation": { "id": "02945e5e-d5a5-48c6-96f6-969c1c32d125" }, "id": "6554364198", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1736780853000, "type": { "value": "text/html" } } ] }
{ "content": "Hello", "conversation": { "id": "02945e5e-d5a5-48c6-96f6-969c1c32d125" }, "id": "6554364198", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1736780853000, "type": { "value": "text/html" } }
An example from wireshark of a similar response to above is below - so you can see the Basic Auth and format of the message (which as per Content-Type is in JSON).
POST /webhook1 HTTP/1.1 Authorization: Basic TXlXZWJob29rVXNlcm5hbWU6TXlXZWJob29rUGFzc3dvcmQ= Content-Type: application/json Content-Length: 2370 Host: my-node-red-server.mydomain.com:1880 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.5.14 (Java/11.0.17) Accept-Encoding: gzip,deflate { "message": [ { "content": "You are now chatting with Banana Man", "conversation": { "id": "fb517e44-7b0a-492a-9be4-cfebcbae2012" }, "id": "3109817384", "sender": { "type": "system" }, "timeStamp": 1734457852000, "type": { "user": { "name": "eir support1", "screenName": "Banana Man" }, "value": "assigned" } }, { "content": "hi", "conversation": { "id": "fb517e44-7b0a-492a-9be4-cfebcbae2012" }, "id": "5278750286", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1734457861000, "type": { "value": "text/html" } }, { "content": "hi", "conversation": { "id": "fb517e44-7b0a-492a-9be4-cfebcbae2012" }, "id": "3468974654", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1734458071000, "type": { "value": "text/html" } }, { "content": "Banana Man has ended the chat", "conversation": { "id": "fb517e44-7b0a-492a-9be4-cfebcbae2012" }, "id": "5981744797", "sender": { "type": "system" }, "timeStamp": 1734462234000, "type": { "value": "complete" } }, { "content": "You are now chatting with Banana Man", "conversation": { "id": "92554d9a-0266-425f-b2c6-fe39f4535d9f" }, "id": "9972824079", "sender": { "type": "system" }, "timeStamp": 1734462258000, "type": { "user": { "name": "eir support1", "screenName": "Banana Man" }, "value": "assigned" } }, { "content": "hi", "conversation": { "id": "92554d9a-0266-425f-b2c6-fe39f4535d9f" }, "id": "5167610718", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1734462262000, "type": { "value": "text/html" } }, { "content": "hello", "conversation": { "id": "92554d9a-0266-425f-b2c6-fe39f4535d9f" }, "id": "8371467370", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1734462286000, "type": { "value": "text/html" } }, { "content": "asdadas", "conversation": { "id": "92554d9a-0266-425f-b2c6-fe39f4535d9f" }, "id": "9160441015", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1734462287000, "type": { "value": "text/html" } }, { "content": "asdasdasd", "conversation": { "id": "92554d9a-0266-425f-b2c6-fe39f4535d9f" }, "id": "8430369050", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1734462288000, "type": { "value": "text/html" } }, { "content": "Banana Man has ended the chat", "conversation": { "id": "92554d9a-0266-425f-b2c6-fe39f4535d9f" }, "id": "7738939127", "sender": { "type": "system" }, "timeStamp": 1734462290000, "type": { "value": "complete" } } ] }
Send Message
ECE Webserver will return a 204 No Content to a successful Send Message request.
Example
curl --location 'https://ece-webserver.mydomain.com/system/ws/v19/clientapplications/messaging/sendmessage' \ --header 'Authorization: Bearer 5a0f0bc4-dc21-44c8-a50b-b12bad7ae41e' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header 'Accept-Language: en-US' \ --data '{ "conversation":{ "id":"02945e5e-d5a5-48c6-96f6-969c1c32d125" }, "type":{ "value":"text/html" }, "content":"Hi, This is <b>Gerry Berry</b>. I want to discuss bananas and the offer 😀" }'
The type value which can be sent are:
- assigned: Chat assigned to an agent
- text/plain: Text message from the end user.
- text/html: Html message from the end user.
- startTyping: End user started typing a message.
- endTyping: End user stopped typing a message.
- enableOffRecordMessages: End user has enabled “offRecord” messages. When this is enabled, the messages sent by the end user will not be masked by the application. Such messages will not be persisted.
- disableOffRecordMessages: End user has disabled “offRecord” messages. When this is disabled, the messages sent by the end user will be masked by the application, based on the configured masking rules.
- acceptAttachment: End user accepted the attachment.
- rejectAttachment: End user rejected the attachment.
- uploadAttachment: End user uploaded an attachment.
- error: Details of error occurred while sending message from webhook to customer.
- delivered: The message was delivered to the end user.
- read: End user read the message.
- geolocation: Geographical location of end user. One of coordinate, address or url must be provided.
End Message
End the Message using PUT, no Body. Note - The URL contains the conversation ID.
A successful End Message request will receive a statusCode of 204 No Content
curl --location --request PUT 'https://ece-webserver.mydomain.com/system/ws/v19/clientapplications/messaging/conversation/02945e5e-d5a5-48c6-96f6-969c1c32d125/end' \ --header 'Authorization: Bearer 5a0f0bc4-dc21-44c8-a50b-b12bad7ae41e' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header 'Accept-Language: en-US' \
Typing Notification
Agent -> Customer Typing Notification
So that you receive notification (to the webhook web server), when the agent starts and stop typing, when sending the Start Conversation request, include the variable sendTypingNotification and set it to yes in the URL as per below example. This is disabled by default.
Once an agent starts to type - the startTyping Notification is sent. Once an agent stops typing it waits about 5 seconds, before sending an endTyping notification (i.e. in case the agent starts to type again).
https://{{ece-web-server}}/system/ws/v19/clientapplications/messaging/conversation/start?searchContactOnAttribute=email.emailAddress&sendTypingNotification=yes
Example of a Start Typing Notification
POST /webhook1 HTTP/1.1 Authorization: Basic TXlXZWJob29rVXNlcm5hbWU6TXlXZWJob29rUGFzc3dvcmQ= Content-Type: application/json Content-Length: 233 Host: webhook-server.mydomain.com:1880 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.5.14 (Java/11.0.17) Accept-Encoding: gzip,deflate { "message": [ { "conversation": { "id": "03d9f1fd-16ac-4f0f-8260-5352f4a4b293" }, "id": "3463141276", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1742919891000, "type": { "value": "startTyping" } } ] }
Example of an End Typing Notification
POST /webhook1 HTTP/1.1 Authorization: Basic TXlXZWJob29rVXNlcm5hbWU6TXlXZWJob29rUGFzc3dvcmQ= Content-Type: application/json Content-Length: 231 Host: webhook-server.mydomain.com:1880 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.5.14 (Java/11.0.17) Accept-Encoding: gzip,deflate { "message": [ { "conversation": { "id": "03d9f1fd-16ac-4f0f-8260-5352f4a4b293" }, "id": "5104121778", "sender": { "type": "user", "user": { "name": "eir support1", "screenName": "Banana Man" } }, "timeStamp": 1742919901000, "type": { "value": "endTyping" } } ] }
Customer -> Agent Typing Notification
Use the SendMessage API and send a value of 'startTyping' or 'endTyping' as per below examples. Note with the Send Message API - you should receive a 204 response (Success - No Content)
Example of an Start Typing Notification
{ "conversation":{ "id":"03d9f1fd-16ac-4f0f-8260-5352f4a4b293" }, "type":{ "value":"startTyping" } }
Example of an End Typing Notification
{ "conversation":{ "id":"03d9f1fd-16ac-4f0f-8260-5352f4a4b293" }, "type":{ "value":"endTyping" } }