Jinja snippets - Dynamic Cards

In the event that you want to print the response from a Webhook as Dynamic Cards, the response may need to be mapped in a certain way in order for it to be displayed as a carousel of cards in the conversation.

The default JSON structure for Cards is as follows:

[{  
"title":"Card Title",
"subtitle":"Card subtitle",
"is_shareable":false,
"image_destination_url":"http://web.site/to/forward/user/",
"image_source_url":"https://www.web.site/with/img.jpg",
"buttons":[]
}]

In some cases, when we create a Webhook to retrieve data from a third-party API, the response will exactly match the structure seen above. However, there may be situations in which the response differs from the default structure. 

See the example Webhook response below:

{
"count": 2,
"next_page": "https://helpcenter.zendesk.com/api/v2/help_center/articles/search.json?page=2&per_page=25&query=a",
"page": 1,
"page_count": 3,
"per_page": 25,
"previous_page": null,
"results": [
{
"draft": false,
"outdated_locales": [],
"body":"......",
"promoted": false,
"comments_disabled": false,
"outdated": false,
"edited_at": "2020-10-29T16:09:15Z",
"position": 0,
"created_at": "2020-06-01T00:49:01Z",
"name": "Creating a ticket in Zendesk Support",
"permission_group_id": 154179,
"author_id": 360687804520,
"url": "https://helpcenter.zendesk.com/api/v2/help_center/en-us/articles/360014149860.json",
"section_id": 360003221899,
"vote_sum": 1,
"updated_at": "2021-01-19T14:53:37Z",
"title": "Creating a ticket in Zendesk Support",
"locale": "en-us",
"vote_count": 1,
"id": 360014149860,
"user_segment_id": null,
"html_url": "https://support.helpcenter.ai/hc/en-us/articles/360014149860-Creating-a-ticket-in-Zendesk-Support",
"result_type": "article",
"snippet": "These custom variables should be seen as a storage location for data either collected from the end user reply to a given",
"label_names": [
"creating a ticket",
"zendesk support"
],
"source_locale": "en-us"
},
{
"draft": false,
"outdated_locales": [],
"body":"......",
"promoted": false,
"comments_disabled": false,
"outdated": false,
"edited_at": "2019-08-06T13:36:47Z",
"position": 0,
"created_at": "2019-03-27T10:54:25Z",
"name": "Supported tokens to be used in modules",
"permission_group_id": 154179,
"author_id": 360687804520,
"url": "https://helpcenter.zendesk.com/api/v2/help_center/en-us/articles/360003873020.json",
"section_id": 360001266459,
"vote_sum": 1,
"updated_at": "2020-08-20T14:32:52Z",
"title": "Supported tokens to be used in modules",
"locale": "en-us",
"vote_count": 1,
"id": 360003873020,
"user_segment_id": null,
"html_url": "https://support.helpcenter.ai/hc/en-us/articles/360003873020-Supported-tokens-to-be-used-in-modules",
"result_type": "article",
"snippet": "20 (2): When provided as metadata by the channel (only Facebook for now) (3): Can be done when selecting \"ResponseTo\" as a",
"label_names": [
"response to",
],
"source_locale": "en-us"
}]
}

If we were to save the entire response above as it is inside a Custom Variable and attempt to print it in the conversation to display some Cards, we would be unsuccessful as the structure does not match what we allow in Cards. 

In order to make the Webhook response above be rendered as Cards, we need to transform the response so that it fits with the default structure. 

Next, we'll provide examples for:

Simple card list

[{% for result in results%}
{"image_source_url":"{{result.body.url}}",
"title":{{result.title|striptags|tojson}},
"subtitle":{{result.body|striptags|truncate(60,True)|tojson}},
"image_destination_url":"{{result.html_url}}",
"is_shareable":false,"buttons":[{ "options":
{ "newtab_url":"{{result.html_url}}", "window_size":"tall"},
"is_active":true, "type":"web_url_tab", "title":"Read more"
}]
}{% if not loop.last %},{% endif%}{% endfor %}]

 

 

Simple card list (only first 5)

This example is almost the same as the previous one. The only difference is that we don't go through the entire list of elements — just the first 5. 

By adding [:5] after "results", you take only the first 5 and skip the rest. This is useful when you don't want to overwhelm the end user with too much information.

[{% for result in results[:5]%}
{"image_source_url":"{{result.body.url}}",
"title":{{result.title|striptags|tojson}},
"subtitle":{{result.body|striptags|truncate(60,True)|tojson}},
"image_destination_url":"{{result.html_url}}",
"is_shareable":false,"buttons":[{ "options":
{ "newtab_url":"{{result.html_url}}", "window_size":"tall"},
"is_active":true, "type":"web_url_tab", "title":"Read more"
}]
}{% if not loop.last %},{% endif%}{% endfor %}]
 

*You can change the number from [:5] to adjust how many elements will be displayed

Card list with filter

In some cases, you will have a long list of articles, and only some of them will have to be displayed. Using a filter, you can include only some or exclude other articles. In this example, we use user_segment_id to do the filtering. Depending on your use case, you can use any criteria, such as the length of the title or the date of creation.

[{% set filter = [550249, 140885, 140785] %}
{% for result in results if result.user_segment_id in filter %}
{"image_source_url":"{{result.body.url}}",
"title":{{result.title|striptags|tojson}},
"subtitle":{{result.body|striptags|truncate(60,True)|tojson}},
"image_destination_url":"{{result.html_url}}",
"is_shareable":false,"buttons":[{ "options":
{ "newtab_url":"{{result.html_url}}", "window_size":"tall"},
"is_active":true, "type":"web_url_tab", "title":"Read more"
}]
}{% if not loop.last %},{% endif%}{% endfor %}]
 

*This filter works by article segment Id ( [550249, 140885, 140785] ). Using this example you can build what you need.

Card list with filter (only first 10)

In cases when we want to combine filtering and display a limited number of cards, we can not know if the first 5 or 10 will pass the filtering criteria. As a solution, we can count each card that is displayed and stop when our count reaches 10 or any other number we want. 

This example uses the filters from the previous example and adds a counting feature to limit the number of displayed cards.

Include only specific user_segment_id

[{% set ftotal= {'total': 0} %}{% set filter = [550, 1408, 1407] %}
{% for result in results if result.user_segment_id in filter %}
{% if ftotal.update({'total': ftotal.total + 1}) %}{% endif %}
{%if ftotal.total<=10 %}{% if ftotal.total !=1 %},
{% endif%}{"image_source_url":"{{result.body.url}}",
"title":{{result.title|striptags|tojson}},
"subtitle":{{result.body|striptags|truncate(60,True)|tojson}},
"image_destination_url":"{{result.html_url}}",
"is_shareable":false,"buttons":[{ "options":
{ "newtab_url":"{{result.html_url}}", "window_size":"tall"},
"is_active":true, "type":"web_url_tab", "title":"Read more"
}]
}{% endif%}{% endfor %}]
 

Include all except one user_segment_id

[{% set ftotal= {'total': 0} %}
{% for result in results if result.user_segment_id != 343435435434%}
{% if ftotal.update({'total': ftotal.total + 1}) %}{% endif %}
{%if ftotal.total<=10 %}{% if ftotal.total !=1 %},{% endif%}{"image_source_url":"{{result.body.url}}",
"title":{{result.title|striptags|tojson}},
"subtitle":{{result.body|striptags|truncate(60,True)|tojson}},
"image_destination_url":"{{result.html_url}}",
"is_shareable":false,"buttons":[{ "options":
{ "newtab_url":"{{result.html_url}}", "window_size":"tall"},
"is_active":true, "type":"web_url_tab", "title":"Read more"
}]
}{% endif%}{% endfor %}]