Sending interactive message via Knit Communication APIs

Interactive messages, like normal text messages, have not only text part but also an interactive component like button or dropdown. Most messaging applications support interactive messaging. For better understanding on Teams/Slack see the below links:

If you visited the above links, you can see that there is substantial difference between the two tools in sending interactive messages. Through Knit, you can unify your messaging stack for Teams and Slack. Let's find out more firstly by looking at Knit interactive message structure. There are two important message sections, non-interactive and interactive.

1. Non interactive section

This section can be used for describing motive and inner details of a message. Currently we support following types of non interactive sections:

  • Text area - This is simple text box section where you can provide your text in markdown format supported by Knit text formatting .
  • Key Value section - This can be used to highlight some key points of message.

These sections can be arranged in input array to design your message with Knit. See the code snippet below:

{
  "sectionType": "textBlock",
  "text": "This is a sample text area section"
}
{
  "sectionType": "keyValueSet",
  "values": [
    {
      "key": "Key 1",
      "value": "Value 1"
    },
    {
      "key": "Key 2",
      "value": "Value 2"
    }
  ]
}

2. Interactive components

This part is includes buttons, dropdown etc. where user can interact with message by making selection among one of the option. Currently we support only one interactive component:

  • Buttons - Every button in a message is treated as single interactive component. It has following fields:
  1. Interactive component type
  2. id -> user passed id for button.
  3. label-> text shown to user on button
  4. value -> user passed value string.
  5. style (optional)

🚧

Button style can only be applied to Slack Buttons

There are three button styles supported by Slack:

  1. primary -> Green button
  2. danger -> Red button
  3. default -> No colour

πŸ“˜

Use an unique component id

Users should pass id and value of component in such way so that it can make sense of these once it is received in payload after user interacts with component.

Our suggestion would be use an unique id for each button. This can help you in routing the Knit's webhook payload to the the right business logic at your end. The value field can be looked at as metadata for the action/interaction and can be used to help with processing the interaction at your end.

3. Destination

This is the end point where user wants Knit to send interaction payload so that it can be further processed.

{
        "sections": [
            {
                "sectionType": "textBlock",
                "text": "This is a sample text"
            },
            {
                "sectionType": "keyValueSet",
                "values": [
                    {
                        "key": "Key 1",
                        "value": "value 1"
                    },
                    {
                        "key": "Key 2",
                        "value": "value 2"
                    }
                ]
            }
 
        ],
        "interactiveComponents": [
            {
                "id": "approveBtn",
                "label": "Approve",
                "value": "value1",
                "style": "primary",
                "interactiveComponentType": "button"
            },
            {
                "label": "Deny",
                "id": "denyBtn",
                "value": "value2",
                "style": "danger",
                "interactiveComponentType": "button"
            },
            {
                "label": "Neutral",
                "id": "neutralBtn",
                "value": "value3",
                "interactiveComponentType": "button"
            }
        ],
        "destination": "https://sample-destination.com"
    }

🚧

Few checks on different keys

  1. Destination must be an "http" or "https" link and should be less than 160 characters.
  2. Component id must be less than 100 characters.
  3. Component value must be less than 70 characters.

Designing your first interactive message workflow

πŸ‘

Before we start

  1. You should have all necessary setup that is needed for sending plain text. Click on Sending plain text with Knit
  2. For slack you must setup Slack Interactive Endpoint in slack app management dashboard under interactivity section.

Let's try to understand interactive messages with a real life scenario. Let's assume that Knit wants to start flexible benefit plan for employees and they want to get response from all employees. Let's crack on and design this workflow.

A reminder before we begin, message can have:

  • Text block describing flexible benefit plan.
  • Key value section to highlight important points of the plan.
  • Key value section to highlight important points of the plan.
  • Destination URL so that interaction payload can be sent .

Below code sample shows example for our use case. It can be tweaked as per user need.

 "interactiveMessage": {
        "sections": [
            {
                "sectionType": "textBlock",
                "text": "Hey!! we are planning to start **flexible benefit plan** across the org to help you save more tax.This can be used to restructure you existing salary into different allowances."
            },
            {
                "sectionType": "keyValueSet",
                "values": [
                    {
                        "key": "Food allownace(pm)",
                        "value": "3300"
                    },
                    {
                        "key": "Telephone allowance(pm)",
                        "value": "2000"
                    },
                    {
                        "key": "Gift allowance(pm)",
                        "value": "500"
                    }
                ]
            },
            {
                "sectionType": "textBlock",
                "text": "If you want to opt for this benefit from coming month, choose the appropriate button below."
            }
        ],
        "interactiveComponents": [
            {
                "id": "approveBtn||flex_benifit",
                "label": "Approve",
                "value": "emp_123",
                "style": "primary",
                "interactiveComponentType": "button"
            },
            {
                "label": "Deny",
                "id": "denyBtn||flex_benifit",
                "value": "emp_123",
                "style": "danger",
                "interactiveComponentType": "button"
            },
            {
                "label": "Not Sure",
                "id": "neutralBtn||flex_benifit",
                "value": "emp_123",
                "interactiveComponentType": "button"
            }
        ],
        "destination": "https://sample-url.com/flexi"
    }

πŸ“˜

Button Id and value naming

  • Button id is made up of functionality (flexible benefit) and button type.
  • Button value gives employee id who have responded
  • Note that button id is unique for each button.

Sending the message using Knit APIs

To send we will be using existing Send Message API with query parameter messageType = "interactive". The below code sample will show the same interactive message payload in Java.

public static void sendInteractiveMessage(String channelId) {
        OkHttpClient client = new OkHttpClient();
        Map<String, Object> map = new HashMap<>();
        String interactiveMessageBody = "{\"sections\":[{\"sectionType\":\"textBlock\",\"text\":\"Hey!! we are planning to start **flexible benifit plan** across the org to help you save more tax.This can be used to restructure you existing salary into different allowances.\"},{\"sectionType\":\"keyValueSet\",\"values\":[{\"key\":\"Food allownace(pm)\",\"value\":\"3300\"},{\"key\":\"Telephone allowance(pm)\",\"value\":\"2000\"},{\"key\":\"Gift allowance(pm)\",\"value\":\"500\"}]},{\"sectionType\":\"textBlock\",\"text\":\"If you want to opt for this benifit from coming month, choose the appropriate button below.\"}],\"interactiveComponents\":[{\"id\":\"approveBtn||flex_benifit\",\"label\":\"Approve\",\"value\":\"emp_123\",\"style\":\"primary\",\"interactiveComponentType\":\"button\"},{\"label\":\"Deny\",\"id\":\"denyBtn||flex_benifit\",\"value\":\"emp_123\",\"style\":\"danger\",\"interactiveComponentType\":\"button\"},{\"label\":\"Not Sure\",\"id\":\"neutralBtn||flex_benifit\",\"value\":\"emp_123\",\"interactiveComponentType\":\"button\"}],\"destination\":\"https://sample-url.com/flexi\"}";
        JsonObject jsonObject = JsonParser.parseString(interactiveMessageBody).getAsJsonObject();
        map.put("interactiveMessage", jsonObject);
        map.put("channelId", channelId);
        map.put("channelType", "dm");

        String body = toJson(map); // convert to json
        System.out.println(body);
        Request request = new Request.Builder()
                .url("https://api.getknit.dev/v1.0/comm.msg.send?messageType=interactive")
                .addHeader("Authorization", "Bearer " + "API_KEY")
                .addHeader("X-Knit-Integration-Id", "Integration Id")
                .post(RequestBody.create(body, JSON))
                .build();
        Response response = client.newCall(request).execute();
        JsonNode jsonNode = mapper.readTree(response.body().string());
        String messageId = jsonNode.at("/data/messageId").asText();

    }

The below images will show how this will look in different messaging platforms:

Slack

MS Teams

Processing payload after interaction

As soon as user clicks on any interactive component, Knit will send you payload on destination set in interactive message. Let's assume user has clicked on Approve and your backend receives the adequate payload. This payload can be further used to store users response and send acknowledgement message back to user using either Send Message API or Update Message API.

{
  "eventId": "ev_vfSGMAUsvRZG6mG6HuI1Fu",
  "eventData": {
    "componentId": "approveBtn||flex_benifit",
    "componentValue": "emp_123",
    "channelId": "D04M0KAD093",
    "messageId": "MTY3OTA0NTYyOS41MDE3Mzk6RDA0TTBLQUQwOTM="
  },
  "eventType": "bot.interactive"
}
 public static void handleInteractiveMessage(String payload) throws IOException {
        JsonNode jsonNode = mapper.readTree(payload);
        String compId = jsonNode.at("/eventData/componentId").asText();
        String compValue = jsonNode.at("/eventData/componentValue").asText();
        String channelId = jsonNode.at("/eventData/channelId").asText();
        String messageId = jsonNode.at("/eventData/messageId").asText();
        // CompValue = employeeId , compId = response String can be fetched using it
        registerFlexiBenifitsResp(compId, compValue);

        // Further You can update the same message calling Knit API
        Map<String, Object> map = new HashMap<>();
        map.put("message", "Your response has been registered!!");
        map.put("channelId", channelId);
        map.put("channelType", "dm");
        map.put("messageId", messageId);
        String body = toJson(map);

        Request request = new Request.Builder()
                .url("https://api.getknit.dev/v1.0/comm.msg.update")
                .addHeader("Authorization", "Bearer " + "API_KEY")
                .addHeader("X-Knit-Integration-Id", "Integration Id")
                .post(RequestBody.create(body, JSON))
                .build();
        Response response = client.newCall(request).execute();
        JsonNode jsonNode = mapper.readTree(response.body().string());

        
    }

    public static void registerFlexiBenifitsResp(String empId, String responseStr) {
        //put your business logic here 
    }

Now we will acknowledge user response by sending acknowledgement message. We will update the same message with a plain text message.

public static void sendAcknowledgementMessage(String channelId) {
        OkHttpClient client = new OkHttpClient();
        Map<String, Object> map = new HashMap<>();
        map.put("message", "Your response has been submitted.");
        map.put("channelId", "D04M0KAD093");
        map.put("channelType", "dm");
        map.put("messageId", "MTY3OTA0NTYyOS41MDE3Mzk6RDA0TTBLQUQwOTM=")

        String body = toJson(map); // convert to json
        Request request = new Request.Builder()
                .url("https://api.getknit.dev/v1.0/comm.msg.update")
                .addHeader("Authorization", "Bearer " + "API_KEY")
                .addHeader("X-Knit-Integration-Id", "Integration Id")
                .post(RequestBody.create(body, JSON))
                .build();
        Response response = client.newCall(request).execute();
        JsonNode jsonNode = mapper.readTree(response.body().string());
        String messageId = jsonNode.at("/data/messageId").asText();
        // This message Id can  be used for further updating message

    }

Here's how it looks in MSTeams:

**MS Teams acknowledgement**

MS Teams acknowledgement

Here's how it looks in Slack:

**Slack acknowledgement**

Slack acknowledgement

That's it. We can't wait to see what you build with Knit's interactive message support!