# HubSpot Account Types @ Learn about the different types of HubSpot accounts and what each one is used for. $ getting-started & --- # HubSpot account types There are several types of HubSpot accounts, each with a distinct purpose. Below, learn about each account type. ## Standard HubSpot accounts A standard HubSpot account is the most common type of account. It’s where you’ll find all the tools, features, and settings included with your HubSpot plan. It can be free or paid, and is used as your production environment. A standard HubSpot account will have access to all the tools and features included with your plan. ## Developer accounts Developer accounts are free accounts intended for creating and managing apps, integrations, and developer test accounts. They're also where you can create and manage App Marketplace listings. Developer accounts and their associated test accounts aren’t connected to a standard HubSpot account, and they can’t sync data or assets with another HubSpot account. Get started by creating a [developer account](https://app.hubspot.com/signup-hubspot/developers). ### Developer test accounts Within developer accounts, you can create up to 10 test accounts to test apps and integrations without affecting any real HubSpot data. Developer test accounts are free HubSpot accounts with access to a 90-day trial of many enterprise features, with the following limitations: - **Marketing** **Hub:** you can only send marketing emails to addresses of users who you've added to your developer test account. - **Content Hub:** the number of pages you can create are subject to the following limits: - **Website pages:** 25 - **Blogging tools:** 1 blog with up to 100 posts - **Landing pages:** 25 - **Workflows:** a maximum of 100,000 records can be enrolled per day in workflows created in a developer test account. If this daily limit is reached: - Any additional attempted enrollment beyond this limit will be dropped. - Users will be informed in app that they reached the daily record enrollment limit, as well as what time the limit will be refreshed. You can create up to 10 test accounts per developer account. This type of account cannot sync data with other accounts, and they can't be connected to a standard HubSpot account. ### Create a developer test account To create a developer test account: - In the main navigation of your developer account, click **Test accounts**. - In the upper right, click **Create developer test account**. - Enter an **account name**, then click **Create**. To access and manage your developer test accounts: - In the main navigation of your developer account, click **Test accounts**. - Click the **name** of the account to enter the account. - To delete the account or renew its product trial periods, click **Actions**, then select **Renew trials** or **Delete**.
{{ column }} | {% endfor %}
apples | oranges | pears |
grapes | blueberries |
{% set var = "string to center" %} before{{ var|center(80) }}after``` ```html
before string to center after``` | Parameter | Type | Description | | --- | --- | --- | | `width` | Number | Specifies the length of whitespace to center the text in. | ## convert_rgb Converts a HEX value to an RGB string. This is useful if you need to convert color variables to RGB to be used with a RGBA CSS declaration. In the example below, the value set by a color module is converted to an RGB value and used in an RGBA CSS declaration. ```hubl {% set my_color = "#FFFFFF" %} {{ my_color|convert_rgb }} {% set my_color2="#000000" %} ``` ```html 255, 255, 255 ``` ## cut Removes a string from a value. This filter can be used to match and cut out a specific part of a string. The parameter specifies the part of the string that should be removed. The example below removes the space and the word world from the original variable value. ```hubl {% set my_string = "Hello world." %} {{ my_string|cut(" world") }} ``` ```html Hello. ``` | Parameter | Type | Description | | --- | --- | --- | | `characters_to_cut` | String | The part of the string that should be removed. | ## datetimeformat (deprecated) This filter has been [deprecated](/reference/cms/hubl/deprecated#datetimeformat). Instead, use the [format_datetime](#format_datetime) filter, which has a more standardized syntax. ## default If the value is undefined it will return the first parameter, otherwise the value of the variable will be printed. If you want to use default with variables that evaluate to false, you have to set the second parameter to `true`. The first example below would print the message if the variable is not defined. The second example applies the filter to an empty string, which is not undefined, but it prints a message due to the second parameter. ```hubl {{ my_variable|default("my_variable is not defined") }} {{ ""|default("the string was empty", true) }} ``` ```html my_variable is not defined the string was empty ``` | Parameter | Type | Description | | --- | --- | --- | | `default_value` | String | The value to return if the variable is undefined. If the variable is defined, the value of the variable will be returned instead. | | `truthy` | Boolean | Set to `true` to use with variables which evaluate to `false`. | ## dictsort Sort a dict and yield (key, value) pairs. Dictionaries are unsorted by default, but you can print a dictionary, sorted by key or value. The first parameter is a boolean to determine, whether or not the sorting is case sensitive. The second parameter determines whether to sort the dict by key or value. The example below prints a sorted contact dictionary, with all the known details about the contact. ```hubl {% for item in contact|dictsort(false, "value") %} {{item}} {% endfor %} ``` ```html A sorted contact dictionary ``` | Parameter | Type | Description | | --- | --- | --- | | `case_sensitive` | Boolean | Determines if sorting is case sensitive. | | `sort_by` | `"key"` | `"value"` | Determines whether to sort by `key` or `value`. | ## difference Returns the difference of two sets or lists. The list returned from the filter contains all unique elements that are in the first list but not the second. ```hubl {{ [1, 2, 3]|difference([2, 3, 4, 5]) }} ``` ```html [1] ``` | Parameter | Type | Description | | --- | --- | --- | | `list` | Array | The second list to compare to for use in finding differences from the original list. | ## divide Divides the current value by a divisor. The parameter passed is the divisor. This filter is an alternative to the / operator. ```hubl {% set numerator = 106 %} {{ numerator|divide(2) }} ``` ```html 53 ``` | Parameter | Type | Description | | --- | --- | --- | | `divisor` | Number | The number to divide the variable by. | ## divisible An alternative to the `divisibleby` expression test, this filter will evaluate to true if the value is divisible by the given number. ```hubl {% set num = 10 %} {% if num|divisible(2) %} The number is divisible by 2 {% endif %} ``` ```html The number is divisible by 2 ``` | Parameter | Type | Description | | --- | --- | --- | | `divisor` | Number | The number to use when evaluating if the value is divisible. | ## escape_html Escapes the content of an HTML input. Accepts a string and converts the characters `&`, `<`, `>`, `‘`, `”`, and `escape_jinjava` into HTML-safe sequences. Use this filter for HubL variables that are used in HTML but should not allow any HTML. ```hubl " %} {{ escape_string|escape_html }} ``` ```html ``` ## escape_attr Escapes the content of an HTML attribute input. Accepts a string and converts the characters `&`, `<`, `‘`, `”`, and `escape_jinjava` into HTML-safe sequences. Use this filter for HubL variables that are being added to HTML attributes. Note that when escaping values of attributes that accept URLs, such as `href`, you should use the `escape_url` filter instead. ```hubl {% set escape_string = "This
` tag, so the whitespace isn't stripped out. The first parameter controls the amount of whitespace and the second boolean toggles whether to indent the first line. ```hubl{% set var = "string to indent" %} {{ var|indent(2, true) }}``` ```html string to indent ``` | Parameter | Type | Description | | --- | --- | --- | | `width` | Number | The amount of whitespace to be applied. | | `indent-first` | Boolean | When set to `true`, the first line will be indented. | ## int Converts the value into an integer. If the conversion doesn’t work it will return `0`. You can override this default using the first parameter. ```hubl {% set string="25" %} {{ string|int + 17 }} ``` ```html 42 ``` | Parameter | Type | Description | | --- | --- | --- | | `default` | Number | Integer to return if the conversion doesn't work. | ## intersect Returns the intersection of two sets or lists. The list returned from the filter contains all unique elements that are contained in both lists. ```hubl {{ [1, 2, 3]|intersect([2, 3, 4, 5]) }} ``` ```html [2, 3] ``` | Parameter | Type | Description | | --- | --- | --- | | `list` | Array | The second list to compare to for use in finding where the list intersects with the original list. | ## ipaddr Evaluates to `true` if the value is a valid IPv4 or IPv6 address. ```hubl {% set ip = "1.0.0.1" %} {% if ip|ipaddr %} The string is a valid IP address {% endif %} ``` ```html The string is a valid IP address ``` ## join Returns a string which is the concatenation of the strings in the sequence. The separator between elements is an empty string per default, you can define it with the optional parameter. The second parameter can be used to specify an attribute to join. ```hubl {% set my_list = [1, 2, 3] %} {% set sep = "---" %} {{ my_list|join }} {{ my_list|join("|") }} {{ my_list|join(sep) }} ``` ```html 123 1|2|3 1---2---3 ``` | Parameter | Type | Description | | --- | --- | --- | | `delimiter` | String | The delimiter to use when concatenating strings. | | `attribute` | HubL Variable | Attribute of value to join in an object. | ## last Returns the last item of a sequence. ```hubl {% set my_sequence = ["Item 1", "Item 2", "Item 3"] %} {% my_sequence|last %} ``` ```html Item 3 ``` ## length Returns the number of items of a sequence or mapping. ```hubl {% set services = ["Web design", "SEO", "Inbound Marketing", "PPC"] %} {{ services|length }} ``` ```html 4 ``` ## list Converts values into a list. Strings will be returned as separate characters unless contained in square bracket sequence delimiters `[ ]`. ```hubl {% set one = 1 %} {% set two = 2 %} {% set three = "three" %} {% set four = ["four"] %} {% set list_num = one|list + two|list + three|list + four|list %} {{ list_num }} ``` ```html [1, 2, t, h, r, e, e, four] ``` ## log Calculates the natural logarithm of a number. ```hubl {{ 10|log }} {{ 65536|log(2) }} ``` ```html 2.302585092994046 16.0 ``` | Parameter | Type | Description | | --------- | ------ | ---------------------------------------- | | `base` | Number | The base to use for the log calculation. | ## lower Converts all letters in a value to lowercase. ```hubl {% set text="Text to MAKE LowercaSe" %} {{ text|lower }} ``` ```html text to make lowercase ``` ## map Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with a list of objects where you're only interested in a certain value of it. The basic usage is mapping on an attribute. For example, if you want to use conditional logic to check if a value is present in a particular attribute of a dict. Alternatively, you can let it invoke a filter by passing the name of the filter and the arguments afterwards. ```hubl {# Usage 1 #} Apply a filter to a sequence: {% set seq = ["item1", "item2", "item3"] %} {{ seq|map("upper") }} {# Usage 2 #} Look up an attribute: {{ content|map("currentState")}} ``` ```hubl Apply a filter to a sequence: [ITEM1, ITEM2, ITEM3] Look up an attribute: [DRAFT] ``` | Parameter | Type | Description | | --------- | ------ | ------------------------------------------- | | `filter` | String | Filter to apply to the sequence of objects. | ## md5 Calculates the [md5 hash](https://en.wikipedia.org/wiki/MD5) of the given object. ```hubl {{ content.absolute_url|md5 }} ``` ```html 923adb4ce05a4c6342c04c80be88d15e ``` ## minus_time Subtracts an amount of time from a datetime object. ```hubl {% set date = "2018-07-14T14:31:30+0530"|strtotime("yyyy-MM-dd'T'HH:mm:ssZ") %} {{ date }} {{ date|minus_time(2, "months") }} ``` ```html 2018-07-14 14:31:30 2018-05-14 14:31:30 ``` | Parameter | Type | Description | | --- | --- | --- | | `diff` | Number | Amount to subtract. | | `timeunit` | String | Valid time units are `nanos` , `micros` , `millis` , `seconds` , `minutes` , `hours` , `half_days` , `days` , `weeks` , `months` , `years` , `decades` , `centuries` , `millennia` , and `eras` . | ## multiply Multiplies a value with a number. Functions the same as the [\* operator](/reference/cms/hubl/operators-and-expression-tests). ```hubl {% set n = 20 %} {{ n|multiply(3) }} ``` ```html 60 ``` ## plus_time Adds an amount of time to a datetime object. ```hubl {% set date = "2018-07-14T14:31:30+0530"|strtotime("yyyy-MM-dd'T'HH:mm:ssZ") %} {{ date }} {{ date|plus_time(5, "days") }} ``` ```html 2018-07-14 14:31:30 2018-07-19 14:31:30 ``` | Parameter | Type | Description | | --- | --- | --- | | `diff` | Number | Amount to subtract. | | `timeunit` | String | Valid time units are `nanos` , `micros` , `millis` , `seconds` , `minutes` , `hours` , `half_days` , `days` , `weeks` , `months` , `years` , `decades` , `centuries` , `millennia` , and `eras` . | ## pprint Pretty print a variable. This prints the type of variable and other info that is useful for debugging. ```hubl {% set this_var ="Variable that I want to debug" %} {{ this_var|pprint }} ``` ```html (String: Variable that I want to debug) ``` ## random Return a random item from the sequence. When using this filter, the page will be [prerendered](/guides/cms/content/performance/prerendering) periodically rather than every time the page content is updated. This means that the filtered content will not be updated on every page reload. This may not be an issue for certain types of content, such as displaying a random list of blog posts. However, if you need content to change randomly on every page load, you should instead use JavaScript to randomize the content client-side. ```hubl {% for content in contents|random %} {% endfor %} ``` ```html ``` ## regex_replace Searches for a regex pattern and replaces with a sequence of characters. The first argument is a RE2-style regex pattern, the second is the replacement string. Learn more about [RE2 regex syntax](https://github.com/google/re2/wiki/Syntax). ```hubl {{ "contact-us-2"|regex_replace("[^a-zA-Z]", "") }} ``` ```html contactus ``` ## reject Filters a sequence of objects by applying an [expression test](/reference/cms/hubl/operators-and-expression-tests) to the object and rejecting the ones with the test succeeding. ```hubl {% set some_numbers = [10, 12, 13, 3, 5, 17, 22] %} {{ some_numbers|reject("even") }} ``` ```html [13, 3, 5, 17] ``` | Parameter | Type | Description | | --- | --- | --- | | `exp_text` | String | The name of the [expression test](/reference/cms/hubl/operators-and-expression-tests#expression-tests) to apply to the object. | ## rejectattr Filters a sequence of objects by applying a test to an attribute of an object and rejecting the ones with the test succeeding. ```hubl {% for content in contents|rejectattr("post_list_summary_featured_image") %} {% endif %} {{ content.post_list_content|safe }} {% endfor %} ``` ```html ``` | Parameter | Type | Description | | --- | --- | --- | | `attribute_name` | String | Specifies the attribute to select. You can access nested attributes using dot notation. | | `exp_test` | String | The name of the [expression test](/reference/cms/hubl/operators-and-expression-tests#expression-tests) to apply to the object. | ## render Renders strings containing HubL early so that the output can be passed into other filters. ```hubl {{ personalization_token("contact.lastname", "default value")|render|lower }} ``` ```html mclaren ``` ## replace Replaces all instances of a substring with a new one. ```hubl {% if topic %}Posts about {{ page_meta.html_title|replace("Blog | ", "") }}
{% endif %} ``` ```htmlPosts about topic name
``` | Parameter | Type | Description | | --- | --- | --- | | `old` | String | The substring that should be replaced. | | `new` | String | Replacement string. | | `count` | Number | If provided, only the firstcount occurrences are replaced. | ## reverse Reverses the object or return an iterator the iterates over it the other way round. To reverse a list use [.reverse()](/reference/cms/hubl/functions#reverse) ```hubl {% set nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] %} {% for num in nums|reverse %} {{ num }} {% endfor %} ``` ```html 10 9 8 7 6 5 4 3 2 1 ``` ## root Calculates the square root of a value. ```hubl {{ 16|root }} {{ 625|root(4) }} ``` ```html 4 5 ``` | Parameter | Type | Description | | ---------- | ------ | ---------------------------------------- | | `nth_root` | Number | The nth root to use for the calculation. | ## round Rounds a number to a given precision. ```hubl {{ 52.5|round }} {{ 52.5|round(0, "floor") }} ``` ```html 53 52 ``` | Parameter | Type | Description | | --- | --- | --- | | `precision` | Number | Specifies the precision of the rounding. | | `rounding_method` | `'common'` (default) | `'ceil'` | `'floor'` | Options include `common` round either up or down (default); `ceil` always rounds up; `floor` always rounds down. | ## safe Mark a value as safe which means that in an environment with automatic escaping enabled this variable will not be escaped. ```hubl {{ content.post_list_content|safe }} ``` ```htmlHTML post content that is not escaped.
``` ## sanitize_html Sanitizes the content of an HTML input for the output of rich text content. Accepts a string, then strips HTML tags that are not allowed. Use this filter for HubL variables that are used in HTML that should allow safe HTML. You can include the following parameters to allow specific types of HTML tags: `FORMATTING`, `BLOCKS`, `STYLES`, `LINKS`, `TABLES`, `IMAGES`. For example, `sanitize_html(IMAGES)`. Using `sanitize_html` will include all parameters in the filter. You can also include a `STRIP` parameter to strip all HTML. All content is run through `escape_jinjava` as well to prevent nested interpretation. ```hubl " %} {{ escape_string|sanitize_html("IMAGES") }} ``` ```html This markup isprinted as text. ``` ## select Filters a sequence of objects by applying a test to the objects and only selecting the ones with the test succeeding. ```hubl {% set some_numbers = [10, 12, 13, 3, 5, 17, 22] %} {{ some_numbers|select("even") }} ``` ```html [10, 12, 22] ``` | Parameter | Type | Description | | ---------- | ------ | ------------------------------------------- | | `exp_text` | String | The expression test to apply to the object. | ## selectattr Filters a sequence of objects by applying a test to an attribute of the objects and only selecting the ones with the test succeeding. ```hubl {% for content in contents|selectattr("post_list_summary_featured_image") %} {% endif %} {{ content.post_list_content|safe }} {% endfor %} ``` ```html Post with featured image ``` | Parameter | Type | Description | | --- | --- | --- | | `attribute_name` | String | The attribute to test for. You can access nested attributes using dot notation. | | `exp_test` | String | The name of the [expression test](/reference/cms/hubl/operators-and-expression-tests#expression-tests) to apply to the object. | | `val` | String | Value to test against. | ## shuffle Randomizes the order of iteration through a sequence. The example below shuffles a standard blog loop. When using this filter, the page will be [prerendered](/guides/cms/content/performance/prerendering) periodically rather than every time the page content is updated. This means that the filtered content will not be updated on every page reload. This may not be an issue for certain types of content, such as displaying a random list of blog posts. However, if you need content to change randomly on every page load, you should instead use JavaScript to randomize the content client-side. ```hubl {% for content in contents|shuffle %} {% endfor %} ``` ```html ``` ## slice Slices an iterator and returns a list of lists containing those items. The first parameter specifies how many items will be sliced, and the second parameter specifies characters to fill in empty slices. ```hubl {% set items = ["laptops", "tablets", "smartphones", "smart watches", "TVs"] %} ``` ```html ``` | Parameter | Type | Description | | --- | --- | --- | | `slices` | Number | How many items will be sliced. | | `filler` | String | Specifies characters to fill in empty slices. | ## sort Sorts an iterable. This filter requires all parameters to sort by an attribute in HubSpot. The first parameter is a boolean to reverse the sort order. The second parameter determines whether or not the sorting is case sensitive. And the final parameter specifies an attribute to sort by. In the example below, posts from a blog are rendered and alphabetized by name. ```hubl {% set my_posts = blog_recent_posts("default", limit=5) %} {% for item in my_posts|sort(False, False, "name") %} {{ item.name }}
{% endfor %} ``` ```html A post
B post
C post
D post
E post
``` | Parameter | Type | Description | | --- | --- | --- | | `reverse` | Boolean | Set to `true` to reverse the sort order. | | `case_sensitive` | Boolean | Set to `true` to make sorting case sensitive. | | `attribute` | String | Attribute to sort by. Omit when sorting a list. | ## split Splits the input string into a list on the given separator. The first parameter specifies the separator to split the variable by. The second parameter determines how many times the variable should be split. Any remaining items would remained group. In the example below, a string of names is split at the `;` for the first four names. ```hubl {% set string_to_split = "Mark; Irving; Helly; Dylan; Milchick; Harmony;" %} {% set names = string_to_split|split(";", 4) %}
I want to truncate this text without breaking my HTML
" %} {{ html_text|truncatehtml(28, "..." , false) }} ``` ```html
I want to truncate this..
``` | Parameter | Type | Description | | --- | --- | --- | | `number_of_characters` | Number | Number of characters to allow before truncating the text. Default is 255. | | `end` | String | Override the default '...' trailing characters after the truncation. | | `breakword` | Boolean | Boolean value. If `true`, the filter will cut the text at length. If `false` (default), it will discard the last word. If using only one of the optional parameters, use keyword arguments, such as `truncatehtml(70, breakwords = false)`. | ## unescape_html Converts text with HTML-encoded entities to their Unicode equivalents. ```hubl {% set escape_string = "me & you" %} {{ escape_string|unescape_html }} ``` ```html me & you ``` ## union Returns the union of two sets or lists. The list returned from the filter contains all unique elements that are in either list. ```hubl {{ [1, 2, 3]|union([2, 3, 4, 5]) }} ``` ```html [1, 2, 3, 4, 5] ``` | Parameter | Type | Description | | --- | --- | --- | | `list` | Array | The second list to union with the original list. | ## unique Extracts a unique set from a sequence or dict of objects. When filtering a dict, such as a list of posts returned by a function, you can specify which attribute is used to deduplicate items in the dict. ```hubl {% set my_sequence = ["one", "one", "two", "three" ] %} {{ my_sequence|unique }} ``` ```html [one, two, three] ``` | Parameter | Type | Description | | --- | --- | --- | | `attr` | String | Specifies the attribute that should be used when filtering a dict value. | ## unixtimestamp Converts a datetime object into a Unix timestamp. You should use this filter only with variables that return a date. Starting September 30, 2024, this filter will no longer return the current date when a null value is passed. After that date, a null value in the filter will return `September 30, 2024`. ```hubl {{ local_dt }} {{ local_dt|unixtimestamp }} ``` ```html 2017-01-30 17:11:44 1485814304000 ``` ## upper Converts all letters in a value to uppercase. ```hubl {% set text="text to make uppercase" %} {{ text|upper }} ``` ```html TEXT TO MAKE UPPERCASE ``` ## urlencode Escapes and URL encodes a string using UTF-8 formatting. Accepts both dictionaries and regular strings as well as pairwise iterables. ```hubl {% set encode_value="Escape & URL encode this string" %} {{ encode_value|urlencode }} ``` ```html Escape+%26+URL+encode+this+string ``` ## urldecode Decodes encoded URL strings back to the original URL. Accepts both dictionaries and regular strings as well as pairwise iterables. ```hubl {% set decode_value="Escape+%26+URL+decode+this+string" %} {{ decode_value|urldecode }} ``` ```html Escape & URL decode this string ``` ## urlize Converts URLs in plain text into clickable links. If you pass the filter an additional integer it will shorten the urls to that number. The second parameter is a boolean that dictates whether the link is rel="no follow". The final parameter lets you specify whether the link will open in a new tab. | Parameter | Type | Description | | --- | --- | --- | | `shorten_text` | Number | Integer that will shorten the urls to desired number. | | `no_follow` | Boolean | When set to `true`, the link will include `rel="no follow"`. | | `target="_blank"` | String | Specifies whether the link will open in a new tab. | ```hubl {{ "http://hubspot.com/"|urlize }} {{ "http://hubspot.com/"|urlize(10,true) }} {{ "http://hubspot.com/"|urlize("",true) }} {{ "http://hubspot.com/"|urlize("",false,target="_blank") }} ``` ```html http://hubspot.com/ http://... http://hubspot.com/ http://hubspot.com/ ``` ## wordcount Counts the number of words in a string. If the string contains HTML, use the `striptags` filter to get an accurate count. ```hubl {% set count_words = "Count the number of words in this variable" %} {{ count_words|wordcount }} ``` ```html 8 ``` ## wordwrap Causes words to wrap at a given character count. This works best in a `` because HubSpot strips whitespace by default. ```hubl {% set wrap_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam efficitur, ipsum non sagittis euismod, ex risus rhoncus lectus, vel maximus leo enim sit amet dui. Ut laoreet ultricies quam at fermentum." %} {{ wrap_text|wordwrap(10) }} ``` ```html Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam efficitur, ipsum non sagittis euismod, ex risus rhoncus lectus, vel maximus leo enim sit amet dui. Ut laoreet ultricies quam at fermentum. ``` | Parameter | Description | | --- | --- | | `character_count` | Number of characters to wrap the content at. | ## xmlattr Creates an HTML/XML attribute string, based on the items in a dict. All values that are neither none nor undefined are automatically escaped. It automatically prepends a space in front of the item if the filter returned something unless the first parameter is false. ```hubl {% set html_attributes = {"class": "bold", "id": "sidebar"} %} ``` ```html ``` | Parameter | Type | Description | | --- | --- | --- | | `autospace` | Boolean | Set to `true` to add a space in front of the item. | # HubL functions @ A reference listing of all of the available HubL functions. $ reference & cms/hubl --- # HubL functions Functions in HubL are similar to filters in that they accept parameters and generate a value. However, not all functions need to be applied to an initial template value, and instead they interact with other areas of your HubSpot environment. If you maintain an older website, you may also want to check out the [list of deprecated HubL functions](/reference/cms/hubl/deprecated). Below, learn more about each HubL function and its syntax. ## append Adds a single item to the end of a list. ```hubl {% set numbers_under_5 = [1,2,3] %} {% do numbers_under_5.append(4) %} {{numbers_under_5}} ``` ```html [1, 2, 3, 4] ``` | Parameter | Type | Description | | --------- | ---- | -------------------------------- | | `item` | Any | Item to be appended to the list. | ## blog_all_posts_url The `blog_all_posts_url` function returns a full URL to the listing page for all blog posts for the specified blog. The example below shows how this function can be used as an anchor's `href`. ```hubl All Marketing blog posts ``` ```html All Marketing blog posts ``` | Parameter | Type | Description | | --- | --- | --- | | `selected_blog` | Blog id or "default" | Specifies which blog to use. The blog id is returned by the [module blog field](/reference/cms/fields/module-theme-fields#blog). | ## blog_author_url The `blog_author_url` function returns a full URL to the specified blog author's listing page. The example below shows how this function can be used as an anchor's `href`. This can be combined with `blog_authors` as shown in that function's examples. ```hubl Brian Halligan ``` ```html Brian Halligan ``` | Parameter | Type | Description | | --- | --- | --- | | `selected_blog` | Blog ID or "default" | Specifies which blog the author's listing page exists in. You can specify a blog by ID or use `"default"` to select the default blog. The blog ID is returned by the [module blog field](/reference/cms/fields/module-theme-fields#blog). | | `author_slug` | String or HubL Var | Specifies which author to link to. Can use either `content.blog_post_author.slug` or a lowercase hyphenated name. Example: `"jane-doe"`. | ## blog_authors The `blog_authors` function returns a sequence of blog author objects for the specified blog, sorted by slug ascending. This sequence can be stored in a variable and iterated through to create custom author post filters. The number of live posts by each author can be accessed with `author.live_posts`. This function has a limit of 250 authors. this function also has a limit of 10 calls per page and per email. The first line of the example below shows how the function returns a sequence of author objects. The rest of the example shows a use case of saving a sequence into a variable and then iterating though the author objects, printing a set of author listing links. The example assumes that the blog has 4 authors. ```hubl {{ blog_authors("default", 250) }} {% set my_authors = blog_authors("default", 250) %}
Hey there
``` ```html true false Hey there ``` | Parameter | Type | Description | | --- | --- | --- | | `color_1`Can also use a variable that stores a hex or RGB color code. For example:`theme.primary_color.color` | | `color_2` | Color | The second color to compare against the first. | | `rating` | String | The WCAG standard to use for rating. Can be either `AA` (default) or `AAA`. | ## color_variant This function lightens or darkens a hex value or color variable by a set amount. The first parameter is the hex color (for example ("#FFDDFF") or a variable storing a hex value. The second parameter is the amount to adjust it by, from 0 to 255. This function can be used in CSS files to create a color variation. Another good use case is to use it with a color parameter of a color module, to allow users to specify a primary color that automatically generates a color variation. In the example below, the hex color #3A539B is stored in a variable called `base_color`. The color is modified by -80 resulting in a darker blue (#00034B). ```hubl {% set base_color ="#3A539B" %} {{ color_variant(base_color, -80) }} ``` ```html #00034b ``` | Parameter | Type | Description | | --- | --- | --- | | `base_color` | HEX color string | The starting color to be altered. For example, `#F7F7F7`. | | `brightness_offset` | Integer | A positive or negative number used to lighten or darken the base color. | ## content_by_id The **`content_by_id`** function returns a landing page, website page or blog post by ID. The only parameter accepted by this function is a numeric content ID. The below example code shows this function in use to generate a hyperlinked list item. This function has a limit of 10 calls per page and per email. ```hubl {% set my_content = content_by_id(4715624297) %} ``` ```html ``` | Parameter | Type | Description | | --------- | ---- | --------------------------------- | | `id` | ID | The ID of the content to look up. | ## content_by_ids Given a list of content IDs, returns a dict of landing page, website page or blog posts matching those IDs. This function takes one parameter, a list of page or blog post IDs to look up, placed within an array. Up to 100 content objects can be passed. The below example code shows this function in use to generate a list of hyperlinked list items. This function has a limit of 10 calls per page and per email. ```hubl {% set contents = content_by_ids([4715624297, 4712623297, 5215624284]) %}After append:
{% do attendees.append("Jon") %} {% set jon_count_after_append = attendees.count("Jon") %} There are now {{jon_count_after_append}} Jon's in the list. ``` ```html There are 1 Jon's in the list.After append:
There are now 2 Jon's in the list. ``` ## crm_associations Gets a list of CRM records associated with another record by its record ID, association category, and association definition ID. This function returns an object with the following attributes: `has_more`, `total`, `offset` and `results`. - `has_more` indicates there are more results available beyond this batch (total > offset). - `total` is the total number of results available. - `offset` is the offset to use for the next batch of results. - _`results`_ returns an array of the specified associated objects matching the function's parameters For security purposes, of the [HubSpot standard object types](https://knowledge.hubspot.com/get-started/manage-your-crm-database#standard-objects) only the `product`, and `marketing_event` objects can be retrieved on a publicly accessible page. Any other standard object type must be hosted on a page which is either [password protected](https://knowledge.hubspot.com/website-pages/password-protect-a-page) or requires a [CMS Membership login](https://knowledge.hubspot.com/website-pages/require-member-registration-to-access-private-content). Custom objects do not have this same restriction. ```hubl {% set associated_contacts = crm_associations(847943847, "HUBSPOT_DEFINED", 2, "limit=3&years_at_company__gt=2&orderBy=email", "firstname,email", false) %} {{ associated_contacts }} ``` ```html {has_more=true, offset=3, total=203, results=[{firstname=Aimee, id=905, email=abanks@company.com}, {firstname=Amy, id=1056, email=abroma@company.com}, {firstname=Abigael, id=957, email=adonahu@company.com}]} ``` This function can be called a maximum of 10 times per page and per email. Each `crm_associations` call can return at most 100 objects. The default limit is 10 objects. | Parameter | Type | Description | | --- | --- | --- | | `id` | ID | ID of the record to find associations from. | | `association category` | String | The category of the association definition. Possible values are `HUBSPOT_DEFINED`, `USER_DEFINED`, and `INTEGRATOR_DEFINED`. This parameter can be omitted for hubspot defined built-in association types. | | `association type id` | Integer | The ID of the association definition to use. For standard HubSpot supported objects see [ID of the association type to use](/guides/api/crm/associations).Otherwise, this association ID can found at the [CRM Objects Schema API](/guides/cms/content/data-driven-content/crm-objects#getting-a-custom-object-type-s-details). | | `query` | String | The `id` of the record OR a query string, delimited by `&`. All expressions are ANDed together. Supported operators are:{{my_type}}
``` ```htmlstr
``` ## unixtimestamp This function returns a unix timestamp when you supply a datetime object. ```hubl {{ unixtimestamp(d) }} ``` ```html 1565983117868 ``` ## update Updates the dict with the elements from another dict object or from an iterable of key-value pairs. Use this function to combine or merge objects. ```hubl {% set dict_var = {"authorName": "Douglas Judy", "authorTitle": "Mastermind" } %} {% do dict_var.update({"authorFriend": "Jake"}) %} {% do dict_var.update({"authorLocation": "unknown"}) %} {{ dict_var }} ``` ```html {authorName=Douglas Judy, authorTitle=Mastermind, authorFriend=Jake, authorLocation=unknown} ``` # If statements @ A practical guide to HubSpot's HubL if statements for CMS developers. $ reference & cms/hubl --- # If Statements You can include conditional logic in your modules and templates by using HubL [if statements](#basic-if-statement-syntax) and [unless statements](#unless-statements). If statements often contain HubL [supported operators](/reference/cms/hubl/operators-and-expression-tests) and can be used to execute [expression tests](/reference/cms/hubl/operators-and-expression-tests#expression-tests). If you're using [personalization tokens](/reference/cms/hubl/functions#personalization-token) within a conditional statement of your email module, you must [enable programmable email for the module](/guides/cms/content/data-driven-content/emails-with-programmable-content). Information passed via the [v3](/guides/api/marketing/emails/transactional-emails#single-send-api) or [v4](/guides/api/marketing/emails/single-send-api) single send APIs will not function within `if` statements, as the templates compile before the information populates. ## Basic if statement syntax HubL uses if statements to help define the logic of a template. The syntax of HubL if statements is very similar to conditional logic in Python. `if` statements are wrapped in [statement delimiters](/reference/cms/hubl/variables-macros-syntax), starting with an opening `if` statement and ending with an `endif`. The example below provides the basic syntax of an if statement, where "condition" would be replaced with the boolean rule that you were going to evaluate as being true of false. ```hubl {% if condition %} If the condition is true print this to template. {% endif %} ``` Now that you have seen the basic syntax, let's look at a few actual examples of basic if statements. The next examples below show if statements that check to see whether or not a HubL module with the name `my_module` and whether a variable named `my_module` are present on a template. Notice that without any operators, the if statement will evaluate whether or not the module is defined in the context of the template. ```hubl {% module "my_module" path="@hubspot/rich_text", label="My rich text module", html="Default module text" export_to_template_context=true %} {% if widget_data.my_module %} A module named "my_module" is defined in this template. {% endif %} {% set my_variable = "A string value for my variable" %} {% if my_variable %} The variable named my_variable is defined in this template. {% endif %} ``` Notice that when evaluating the HubL module, the module name is left in quotes within the `if` statement and while testing the variable no quotes are used around the variable name. In both examples above, the module and the variable exist in the template, so the statements evaluate to print the markup. Please note that these examples are only testing whether the module and variable are defined, not whether or not they have a value. Now let's look at an `if` statement that evaluates whether a module has a value, instead of evaluating whether it exists on the template. To do this, we need to use the [export_to_template_context](/reference/cms/modules/export-to-template-context) parameter. In the example below, if the text module is valued in the content editor, the markup would print. If the module's text field were cleared, no markup would render. If you are working within custom modules, there is a simplified `widget.widget_name` syntax outlined in the [example here](/reference/cms/modules/configuration). ```hubl {% module "product_names" path="@hubspot/text", label="Enter the product names that you would like to render the coupon ad for", value="all of our products", export_to_template_context=True %} {% if widget_data.product_names.value %} {% endif %} ``` ```html ``` ## Using elif and else `if` statements can be made more sophisticated with additional conditional statements or with a rule that executes when the condition or conditions are false. `elif` statements allow you to add additional conditions to your logic that will be evaluated after the previous condition. **`else`** statements define a rule that executes when all other conditions are false. You can have an unlimited number of `elif` statements within a single if statement, but only one `else` statement. Below is the basic syntax example of if statement that uses the [\<= operator](/reference/cms/hubl/operators-and-expression-tests#comparison) to check the value of a variable. In this example, the template would print: "Variable named number is less than or equal to 6." ```hubl {% set number = 5 %} {% if number <= 2 %} Variable named number is less than or equal to 2. {% elif number <= 4 %} Variable named number is less than or equal to 4. {% elif number <= 6 %} Variable named number is less than or equal to 6. {% else %} Variable named number is greater than 6. {% endif %} ``` Below is one more example that uses a choice module to render different headings for a careers page, based on the department chosen by the user. The example uses the [\== operator](/reference/cms/hubl/operators-and-expression-tests#comparison), to check for certain predefined values in the choice module. ```hubl {% choice "department" label="Choose department", value="Marketing", choices="Marketing, Sales, Dev, Services" export_to_template_context=True %} {% if widget_data.department.value == "Marketing" %}||
in JavaScript. Learn more about using `or` operators below. |
| `is` | Joins two operands for an affirmative statement. |
| `not` | Negates a statement, in conjunction with `is`. |
| `(expr)` | Group an expression for the order of operations. For example, `(10 - 2) * variable`. |
| `?` | The [ternary operator](/reference/cms/hubl/if-statements) can be used to quickly write conditional logic. Accepts 3 arguments: expression, true condition, false condition. Evaluates an expression and returns the corresponding condition. |
**Using and/or operators**
In HubL, the `or` operator behaves like the `or` operator in Python and the `||` operator in JavaScript. It will return the first operand if the expression evaluates as true, otherwise it will return the second operand. A common use case for the `or` operator is setting a fallback value when a variable value isn't defined.
```hubl
Two non-empty strings:
{{ "a" or "b" }}
Empty string and non-empty string:
{{ "" or "b" }}
Defining a fallback value:
{{ some_variable or "default value" }}
```
However, the `and` operator behaves differently than the `and` operator in Python and the `&&` operator in JavaScript. In HubL, `and` will always return a boolean value: when the expression evaluates as true, `true` is returned, otherwise it will return `false`. The Python and JavaScript operators, on the other hand, will return an operand value based on whether the statement evaluates as true or false.
```hubl
Two non-empty strings:
{{ "a" and "b" }}
Empty string and non-empty string:
{{ "" and "b" }}
```
In HubL, empty lists (`[]`) and empty dicts (`{}`) are considered falsy. This is equivalent to the behavior in Python, but different from JavaScript, where `[]` and `{}` are truthy.
```hubl
Empty list and non-empty list:
{{ [] or [2] }}
Empty dict and non-empty dict:
{{ {} and {b: 2} }}
```
### Other HubL operators
Below are other important HubL operators that can be used to perform various tasks.
| Symbol | Description |
| --- | --- |
| `in` | Checks to see if a value is in a sequence. |
| `is` | Performs an [expression test](/reference/cms/hubl/operators-and-expression-tests#expression-tests). |
| |
| Applies a filter. |
| `~` | Concatenates values. |
## Expression tests
Expression tests are various boolean conditions that can be evaluated by using logical operators.
### boolean
Tests whether the object is boolean (in a strict sense, not in its ability to evaluate to a truthy expression).
```hubl
{% set isActive = false %}
{% if isActive is boolean %}
isActive is a boolean
{% endif %}
```
```html
isActive is a boolean
```
### containing
Tests whether a list variable has a value in it.
```hubl
{% set numbers = [1, 2, 3] %}
{% if numbers is containing 2 %}
Set contains 2!
{% endif %}
```
```html
Set contains 2!
```
### containingall
Tests if a list variable contains all of the values of another list.
```hubl
{% set numbers = [1, 2, 3] %}
{% if numbers is containingall [2, 3] %}
Set contains 2 and 3!
{% endif %}
{% if numbers is containingall [2, 4] %}
Set contains 2 and 4!
{% endif %}
```
```html
Set contains 2 and 3!
```
### defined
Tests whether a variable is defined within the context of the template. While you can use this expression test, writing an if statement without any operators will default to checking whether or not the variable is defined.
In the example below, a color module's color parameter is tested. If the color parameter had no value, the template would render a default black background color. If it is defined, it renders the background color set by the user.
```hubl
{% color "my_color" color="#930101", export_to_template_context=True %}
```
```html
```
### divisibleby
Tests whether an object is divisible by another number.
For example, below a for loop is created that iterates through a list of types of animals. Each type of animal gets printed in a div, and every 5th div has different inline styling applied (width:100%). This concept could be applied to a blog where different markup is rendered for a certain pattern of posts. To learn more about for loops and loop.index, [check out this article](/reference/cms/hubl/loops).
```hubl
{% set animals = ["lions", "tigers", "bears", "dogs", "sharks"] %}
{% for animal in animals %}
{% if loop.index is divisibleby 5 %}
{% else %}
{% endif %}
{% endfor %}
```
```html
```
### equalto
Tests whether a variable's value is equal to a constant or another variable. You can also use the operator `==` to do the same test.
In the example below, the width of the blog posts is adjusted based on the total number of posts in the loop. The example output assumes there were 4 posts in the blog.
```hubl
{% for content in contents %}
{% if loop.length is equalto 2 %}
{% elif loop.length is equalto 3 %}
{% elif loop.length is equalto 4 %}
{% else %}
{% endif %}
{% endfor %}
```
```html
```
### even
Tests whether a numeric variable is an even number.
The example below shows a simplified blog listing loop, where if the current iteration of the loop is even, a class of `even-post` is assigned to the post item div. Otherwise, a class of `odd-post` is assigned.
```hubl
{% for content in contents %}
{% if loop.index is even %}
{% else %}
{% endif %}
{% endfor %}
```
```html
```
### float
Tests whether a numeric variable is a floating-point number.
```hubl
{% set quantity = 1.20 %}
{% if quantity is float %}
quantity is a floating point number
{% endif %}
```
```html
quantity is a floating-point number
```
### integer
Tests whether a variable is an integer.
```hubl
{% set quantity = 120 %}
{% if quantity is integer %}
Quantity is an integer
{% endif %}
```
```html
Quantity is an integer
```
### iterable
Tests whether a variable can be looped through.
This example checks a variable called `jobs` to see if it can be iterated through. Since the variable contains a list of jobs, the [if statement](/reference/cms/hubl/if-statements) would evaluate to `true`, and the loop would run. If the variable had contained a single value, the if statement would print that value with different markup instead. [Learn more about for loops](/reference/cms/hubl/loops).
```hubl
{% set jobs = ["Accountant", "Developer", "Manager", "Marketing", "Support"] %}
{% if jobs is iterable %}
The headline and subheader tells us what you're offering, and the form header closes the deal. Over here you can explain why your offer is so great it's worth filling out a form for.
Remember:
The headline and subheader tells us what you're offering, and the form header closes the deal. Over here you can explain why your offer is so great it's worth filling out a form for.
Remember:
` subheader. ```hubl {% section_header "section_header" %} {% section_header "my_section_header" subheader="A more subdued subheader", header="A clear and bold header", label="Section Header" %} ``` ```html
``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `header` | String | Text to display in header. | `"A clear and bold header"` | | `subheader` | String | Text to display in subheader. | `"A more subdued subheader"` | | `heading_level` | String | The semantic HTML heading level. h1 to h6 are supported. | `"h1"` | ## Simple menu Simple menus allow you to create basic [navigation menus](/guides/cms/content/menus-and-navigation) that can be modified at the page level. Unlike regular menu modules, simple menus are not managed from the Navigation screen in Website Settings, but rather from the template and page editors. You can use [block syntax](/reference/cms/modules/using-modules-in-templates#block-syntax) to set up a default menu tree. ```hubl {% simple_menu "simple_menu" %} {% simple_menu "my_simple_menu" orientation="horizontal", label="Simple Menu" %} Block Syntax Example: {% widget_block simple_menu "block_simple_menu" overrideable=True, orientation="horizontal", label="Simple Menu" %} {% widget_attribute "menu_tree" is_json=True %}[{"contentType": null, "subCategory": null, "pageLinkName": null, "pageLinkId": null, "isPublished": false, "categoryId": null, "linkParams": null, "linkLabel": "Home", "linkTarget": null, "linkUrl": "http://www.hubspot.com", "children": [], "isDeleted": false}, {"contentType": null, "subCategory": null, "pageLinkName": null, "pageLinkId": null, "isPublished": false, "categoryId": null, "linkParams": null, "linkLabel": "About", "linkTarget": null, "linkUrl": "http://www.hubspot.com/internet-marketing-company", "children": [{"contentType": null, "subCategory": null, "pageLinkName": null, "linkUrl": "http://www.hubspot.com/company/management", "isPublished": false, "children": [], "linkParams": null, "linkLabel": "Our Team", "linkTarget": null, "pageLinkId": null, "categoryId": null, "isDeleted": false}], "isDeleted": false}, {"contentType": null, "subCategory": null, "pageLinkName": null, "pageLinkId": null, "isPublished": false, "categoryId": null, "linkParams": null, "linkLabel": "Pricing", "linkTarget": null, "linkUrl": "http://www.hubspot.com/pricing", "children": [], "isDeleted": false}]{% end_widget_attribute %} {% end_widget_block %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `orientation` | Enumeration | Defines classes of menu markup to allow to style the orientation of menu items on the page. Possible values include `"horizontal"` and `"vertical"`. | `"horizontal"` | | `menu_tree` | JSON | Menu structure including page link names and target URLs. | `[]` | ## Social sharing Social sharing tags generate social media icons that can be used to share a particular page. This module can be used with [block syntax](/reference/cms/modules/using-modules-in-templates#block-syntax) to customize the icon images and more. ```hubl {% social_sharing "social_sharing" %} {% social_sharing "my_social_sharing" use_page_url=True %} Block Syntax Example: {% widget_block social_sharing "my_social_sharing" label="Social Sharing", use_page_url=True, overrideable=True %} {% widget_attribute "pinterest" is_json=True %}{"custom_link_format": "", "pinterest_media": "http://cdn1.hubspot.com/hub/158015/305390_10100548508246879_837195_59275782_6882128_n.jpg", "enabled": true, "network": "pinterest", "img_src": "https://static.hubspot.com/final/img/common/icons/social/pinterest-24x24.png"}{% end_widget_attribute %} {% widget_attribute "twitter" is_json=True %}{"custom_link_format": "", "enabled": true, "network": "twitter", "img_src": "https://static.hubspot.com/final/img/common/icons/social/twitter-24x24.png"}{% end_widget_attribute %} {% widget_attribute "linkedin" is_json=True %}{"custom_link_format": "", "enabled": true, "network": "linkedin", "img_src": "https://static.hubspot.com/final/img/common/icons/social/linkedin-24x24.png"}{% end_widget_attribute %} {% widget_attribute "facebook" is_json=True %}{"custom_link_format": "", "enabled": true, "network": "facebook", "img_src": "https://static.hubspot.com/final/img/common/icons/social/facebook-24x24.png"}{% end_widget_attribute %} {% widget_attribute "email" is_json=True %}{"custom_link_format": "", "enabled": true, "network": "email", "img_src": "https://static.hubspot.com/final/img/common/icons/social/email-24x24.png"}{% end_widget_attribute %} {% end_widget_block %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `use_page_url` | Boolean | If true, the module shares the URL of the page by default. | `True` | | `link` | String | Specifies a different URL to share, if `use_page_url` is false. | | | `pinterest` | JSON | Parameters for Pinterest link format and icon image source. | `See block syntax example, above` | | `twitter` | JSON | Parameters for Twitter link format and icon image source. | `See block syntax example, above` | | `linked_in` | JSON | Parameters for LinkedIn link format and icon image source. | `See block syntax example, above` | | `facebook` | JSON | Parameters for Facebook link format and icon image source. | `See block syntax example, above` | | `email` | JSON | Parameters for email sharing link format and icon image source. | `See block syntax example, above` | ## Spacer A spacer tag generates an empty span tag. This tag can be styled to act as a spacer. In drag and drop layouts, the spacer module is wrapped in a container with a class of span1-span12 to determine how much space the module should take up in the twelve column responsive grid. ```hubl {% space "space" %} {% space "spacer" label="Horizontal Spacer" %} ``` ```html ``` ## System page tags The following tags can be used on [system pages](/guides/cms/content/templates/overview#system-pages), such as the password reset or email subscription pages. ### Email backup unsubscribe The backup unsubscribe tag renders for email recipients, if HubSpot is unable to determine their email address, when that recipient tries to unsubscribe. This tag renders a form for the contact to enter his or her email address to unsubscribe from email communications. It should be used on an [Unsubscribe Backup system template.](https://knowledge.hubspot.com/design-manager/use-system-templates-to-customize-error-subscription-and-password-prompt-pages) ```hubl {% email_simple_subscription "email_simple_subscription" %} {% email_simple_subscription "email_simple_subscription" header="Email Unsubscribe", input_help_text="Your email address:", input_placeholder="email@example.com", button_text="Unsubscribe", label="Backup Unsubscribe" %} ``` ```htmlIf this is not your email address, please ignore this page since the email associated with this page was most likely forwarded to you.
"` | | `unsubscribe_single_text` | String | Renders text in a `` above the subscription options. | `"Uncheck the types of emails you do not want to receive:"` | | `unsubscribe_all_text` | String | Renders text in a `
` above the unsubscribe from all emails checkbox input. | `"Or check here to never receive any emails:"` | | `unsubscribe_all_unsubbed_text` | String | Populates text within a `
` that renders, if a contact is currently unsubscribed from all emails. | `"You are presently unsubscribed from all of our emails. Would you like to receive our emails again?"` | | `unsubscribe_all_option` | String | Sets the text next to the unsubscribe from all emails checkbox input. | `"Unsubscribe me from all mailing lists."` | | `button_text` | String | Sets the text of the submit button that updates subscription preferences. | `"Update email preferences"` | | `resubscribe_button_text` | String | Sets the text of the submit button for when contacts are resubscribing. | `"Yes, resubscribe me!"` | ### Email subscriptions confirmation The email subscriptions update confirmation is a module that can be added to the thank you template for when a recipient updates his or her subscription preferences or unsubscribes. It should be used on a [Subscription Preference system template.](https://knowledge.hubspot.com/design-manager/use-system-templates-to-customize-error-subscription-and-password-prompt-pages) ```hubl {% email_subscriptions_confirmation "email_subscriptions_confirmation" %} {% email_subscriptions_confirmation "email_subscriptions_confirmation" label="Subscriptions Update Confirmation", unsubscribe_all_success="You have successfully unsubscribed from all email communications.", subscription_update_success="You have successfully updated your email preferences.", subheader_text="\n If this is not your email address, please ignore this page since the email associated with this page was most likely forwarded to you.\n" %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `header` | String | Renders text in an h1 tag above the unsubscribe form. | `"Communication Preferences"` | | `subheader_text` | String | Populates text above the confirmation message. | `"
If this is not your email address, please ignore this page since the email associated with this page was most likely forwarded to you.
"` | | `unsubscribe_all_success` | String | Sets the text that will display when someone unsubscribes from all email communications. | `"You have successfully unsubscribed from all email communications."` | | `subscription_update_success` | String | Sets the text when a recipient updates his or her subscription preferences. | `"You have successfully updated your email preferences."` | ### Membership login Creates a login form to provide access to [private content](https://knowledge.hubspot.com/website-pages/require-member-registration-to-access-private-content). ```hubl {% member_login "my_login" %} {% member_login "my_login" email_label="Email", password_label="Password", remember_me_label="Remember Me", reset_password_text="Forgot your password?", submit_button_text="Login", show_password="Show password" %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `email_label` | String | The label for the email entry field. | `"Email"` | | `password_label` | String | The label for the password entry field. | `"Password"` | | `remember_me_label` | String | The label for the "Remember Me" checkbox. | `"Remember Me"` | | `reset_password_text` | String | The text for the password reset hyperlink. | `"Forgot your password?"` | | `submit_button_text` | String | The text for the submit button. | `"Login"` | | `show_password` | String | The text for the password reveal link. | `"Show password"` | ### Membership registration Creates a form to register for access to [private content](https://knowledge.hubspot.com/website-pages/require-member-registration-to-access-private-content). ```hubl {% member_register "my_register" %} {% member_register "my_register" email_label="Email", password_label="Password", password_confirm_label="Confirm Password", submit_button_text="Save Password", show_password="Show password" %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `email_label` | String | The label for the email entry field. | `"Email"` | | `password_label` | String | The label for the password entry field. | `"Password"` | | `password_confirm_label` | String | The label for the password confirmation field. | `"Confirm Password"` | | `submit_button_text` | String | The text for the submit button. | `"Save Password"` | | `show_password` | String | The text for the password reveal link. | `"Show password"` | ### Password reset request Creates a form to send a password reset email for accessing password-protected pages. ```hubl {% password_reset_request "my_password_reset_request" %} {% password_reset_request "my_password_reset_request" email_label="Email", submit_button_text="Send Reset Email" %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `email_label` | String | The label for the email entry field. | `"Email"` | | `submit_button_text` | String | The text for the submit button. | `"Send Reset Email"` | | `password_reset_message` | String | The message that displays after requesting the password reset email. | `False` | ### Password reset Renders a password reset form for accessing password-protected pages. ```hubl {% password_reset "my_password_reset" password_label="Password", password_confirm_label="Confirm Password", submit_button_text="Save password", show_password="Show password" %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `password_label` | String | The text label for the password input field. | `"Email"` | | `password_confirm_label` | String | The text label for the password confirmation input field. | `"Send Reset Email"` | | `submit_button_text` | String | The text label for the form submit button. | `False` | | `show_password` | String | The text label for the button to unhide the entered password value. | `False` | | `password_requirements` | String | The text label that describes password requirements. | `False` | ### Password prompt Adds a password prompt to password-protected pages. ```hubl {% password_prompt "password_prompt" %} {% password_prompt "my_password_prompt" submit_button_text="Submit", bad_password_message="Sorry, please try again.\n", label="Password Prompt" %} ``` ```html ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `submit_button_text` | String | Label for button below password entry field. | `"Submit"` | | `bad_password_message` | String | Message displayed if incorrect password entered. | `"Sorry, please try again.
"` | | `password_placeholder` | String | Defines placeholder text within the password field. | `"Password"` | ## Text Creates a single line of text. This tag can be useful to be mixed into your markup, when used in conjunction with the `no_wrapper=True` parameter. For example, if you wanted your end users to be able to define a destination of a predefined anchor, you could populate the `href` with a text module with `no_wrapper=True`. ```hubl {% text "text" %} {% text "simple_text_field" label="Enter text here", value="This is the default value for this text field" %} ``` ```html ``` | Parameter | Type | Description | | --------- | ------ | ---------------------------------------------------- | | `value` | String | Sets the default text of the single line text field. | ## Textarea A textarea is similar to a text module in that it allows users to enter plain text, but it gives them a larger area to work in the content editor. This module does not support HTML. If you want to use directly within a predefined wrapping tag, add the `no_wrapper=true` parameter. ```hubl {% textarea "my_textarea" %} {% textarea "my_textarea" label="Enter plain text block", value="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean a urna quis lacus vehicula rutrum.", no_wrapper=True %} ``` ```html Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean a urna quis lacus vehicula rutrum. ``` | Parameter | Type | Description | | --------- | ------ | -------------------------------------- | | `value` | String | Sets the default text of the textarea. | ## Video Player Render a video player for a video file from the file manager that has the _Allow embedding, sharing, and tracking_ setting turned on. ```hubl {% video_player "embed_player" %} {% video_player "embed_player" overrideable=False, type="scriptV4", hide_playlist=True, viral_sharing=False, embed_button=False, width="600", height="375", player_id="6178121750", style="", conversion_asset="{"type":"FORM","id":"9a77c63f-bee6-4ff8-9202-b0af020ea4b2","position":"POST"}" %} ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `hide_playlist` | Boolean | Hide the video playlist. | `True` | | `playlist_color` | String | A HEX color value for the playlist. | | | `play_button_color` | String | A HEX color value for the play and pause buttons. | `#2A2A2A` | | `embed_button` | Boolean | Display embed button on the player | `False` | | `viral_sharing` | Boolean | Display the social networks sharing button on the player. | `False` | | `width` | Number | Width of the embedded video player. | `Auto` | | `height` | Number | Height of the embedded video player. | `Auto` | | `player_id` | Number | The `player_id` of the video to embed. | | | `style` | String | Additional style for player. | | | `conversion_asset` | JSON | Event setting for player. Can render CTA or Form before or after video plays. This parameter takes a JSON object with three parameters: type (FORM or CTA), id (The guid of the type object), position (POST or PRE). | `See above example` | | `placeholder_alt_text` | String | The video's alt text. | | # HubL variables & macros syntax @ Learn how to use HubL variables & macros to build dynamic pages on HubSpots CMS and emails. $ reference & cms/hubl --- # HubL variables & macros syntax HubL uses variables to store and output values to the template. Variables can be used in template logic or iterated through with for loops. In addition to variables, macros are another useful tool for printing repetitive yet dynamic sections of code throughout your templates. Variables are expressions delimited by `}}`. The basic syntax of variables is as follows: ```hubl // variables {{ variable }} {{ dict.attribute }} ``` ## Variables Variables are either a single word in an expression or an attribute of a dictionary. HubL uses Python-based data structures called dictionaries or **dicts** to store various sets of variables. For example, HubSpot uses a dictionary "content" to house many attributes that pertain to the content created with that template. For example the `content.absolute_url` prints the URL of the specific piece of content. HubSpot has many predefined variables that can be used throughout your page, blog, and email templates. We have a [reference list of variables](/reference/cms/hubl/variables), you can also view the [developer info](/guides/cms/debugging/troubleshooting#developer-info) when browsing any page from your account to see the variables available within that page.. In addition to printing the values of variables and dictionary attributes in a template, you can also define your own variables. You can store strings, booleans, integers, sequences, or create dictionaries within a single variable. Variables are defined within statement delimiters using the word "set". Once stored, variables can then be printed by stating the variable name as an expression. Below you can see various types of information stored in variables and then printed. Variables should either be single words or use underscores for spaces (ie my_variable). **HubL does not support hyphenated variable names.** ```hubl {% set string_var = "This is a string value stored in a variable" %} {{ string_var}} {% set bool_var = True %} {{ bool_var}} {% set int_var = 53 %} {{ int_var}} {% set seq_var = ["Item 1", "Item 2", "Item 3"] %} {{ seq_var}} {% set var_one = "String 1" %} {% set var_two = "String 2" %} {% set sequence = [var_one, var_two] %} {{ sequence }} {% set dict_var = {"name": "Item Name", "price": "$20", "size":"XL"} %} {{ dict_var.price }} ``` ```html This is a string value stored in a variable True 53 [Item1, Item2, Item3] [String 1, String 2] $20 ``` Each example above stores a different type of variable, with the final example storing two different variables in a sequence. In addition to printing values, variables can be used in [if statements](/reference/cms/hubl/if-statements), as [filter](/reference/cms/hubl/filters) parameters, as [function](/reference/cms/hubl/functions) parameters, as well as iterated through with [for loops](/reference/cms/hubl/loops) (sequence variables only). One common usage is to use variables to define common CSS values in your stylesheet. For example, if you have a color that you use over and over again throughout your CSS file. That way, if you need to change that color, you can change the variable value, and all references to that variable will be updated, the next time that you publish the file. ```hubl {% set primary_color = "#F7761F" %} a { color: {{ primary_color }}; {# prints variable HEX value #} } ``` ```css a { color: #f7761f; } ``` ## Macros HubL macros allow you to print multiple statements with a dynamic value. For example, if there is a block of code that you find yourself writing over and over again, a macro may be a good solution, because it will print the code block while swapping out certain arguments that you pass it. The macro is defined, named, and given arguments within a HubL statement. The macro is then called in a statement that passes its dynamic values, which prints the final code block with the dynamic arguments. The basic syntax of a macro is as follows: ```hubl {% macro name_of_macro(argument_name, argument_name2) %} {{ argument_name }} {{ argument_name2 }} {% endmacro %} {{ name_of_macro("value to pass to argument 1", "value to pass to argument 2") }} ``` If your macro is returning whitespace in the form of new lines, you can strip whitespace in templates by hand. If you add a minus sign (`-`) to the start or end of a block, a comment, or a variable expression, the whitespaces before or after that block will be removed. ```hubl {% macro name_of_macro(argument_name, argument_name2) -%} {{ argument_name }} {{ argument_name2 }} {%- endmacro %} ``` Below shows a practical application of a macro to print a CSS3 properties with the various vendor prefixes, with a dynamic value. This allows you to print 5 lines of code with a single macro tag. ```hubl {% macro trans(value) %} -webkit-transition: {{value}}; -moz-transition: {{value}}; -o-transition: {{value}}; -ms-transition: {{value}}; transition: {{value}}; {% endmacro %} a { {{ trans("all .2s ease-in-out") }} } ``` ```css a { -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; -o-transition: all 0.2s ease-in-out; -ms-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } ``` Macros introduce the ability to have recursive code. To prevent reliability and performance issues you can only nest macros 20 levels deep. If you go over this limit you will get the error: `max recursion limit of 20 reached for macro` is added into a macro in addition to the two arguments. ```hubl {% macro render_dialog(title, class) %} {% endmacro %} {% call render_dialog("Hello World", "greeting") %}
This is a paragraph tag that I want to render in my.
{% endcall %} ``` ```html ``` ## Import Another useful feature of macros is that they can be used across templates by importing one template file into another. To do this you will need to use the **import** tag. The import tag will let you specify a Design Manager file path to the template that contains your macros and give the macros a name in the template that you are including them in. You can then pass values into these macros without needing to redefine them. For example, let's say that you have a .html template file that contains the following 2 macros. One macro is defined to set up a header tag and one is defined to generate a footer tag. This file is saved in Design Manager with the name `my_macros.html`. ```hubl {% macro header(tag, title_text) %}Some content
{{ header_footer.footer("h3:", "Company footer info") }} ``` ```htmlSome content
``` ## From If you want to only import specific macros, instead of all macros contained in a separate .html file, you can use the **from** tag. With the from tag, specify only the macros that you want to import. Generally, using **import** will provide more flexibility, but this alternative is also supported. The example below accesses the same `my_macros.html` file from the previous section of this article. But this time instead of importing all macros, it accesses only the footer macro. ```hubl {% from "custom/page/web_page_basic/my_macros.html" import footer %} {{ footer("h2", "My footer info") }} ``` ```html ``` ## Variables within loops Any variables defined within loops are limited to the scope of that loop and cannot be called from outside of the loop. You can call variables that are defined outside of a loop, from within a loop, but not the other way around. You can also use functions in order to mutate objects for settings values on dict's or performing list operations. The following example is using the [`.update` list operation](/reference/cms/hubl/functions#update): ```hubl {% set obj = {val : 0} %} {% for i in range(0, 10) %} {% do obj.update({val: obj.val + i }) %} {% endfor %} {{ obj.val }} ``` ```html 45 ``` # HubL variables @ HubSpot templates can use a host of predefined variables that can be used to render useful website and email elements. This page is a reference listing of those variables. $ reference & cms/hubl --- # HubL variables HubSpot templates can use a host of predefined variables that can be used to render useful website and email elements. This page is a reference listing of those variables. [Learn more about creating your own variables](/reference/cms/hubl/variables-macros-syntax) in a [HubL template](/guides/cms/content/templates/types/html-hubl-templates) or [module](/guides/cms/content/modules/overview). While most of the variables listed on this page are optional, there are a few variables that are required for creating emails and pages from your templates. The variables listed below can be used individually by wrapping them in the `}}` delimiter as noted on our [Variables and Macros page](/reference/cms/hubl/variables-macros-syntax). You can optionally use these variables with other parts of the HubL Templating Language such as [loops](/reference/cms/hubl/loops), [filters](/reference/cms/hubl/filters), [functions](/reference/cms/hubl/functions), [tags](/reference/cms/hubl/tags/standard-tags), and more. ## Variables available in all templates The HubL variables below can be used in email, page, or blog templates. To see additional information about what these variables output, you can use the [pprint filter](/reference/cms/hubl/filters#pprint), as shown below. ```hubl {% set variable = content %} {{variable|pprint}} ``` ```html (ContentMeta: { "canonicalUrl" : "https://www.website.com/url-slug", "deferDynamicValues" : false, "featuredImageAltText" : "", "featuredImageHeight" : 0, "featuredImageUrl" : "", "featuredImageWidth" : 0, "htmlTitle" : "", "linkRelCanonicalUrl" : "https://www.website.com/url-slug", "metaDescription" : "", "metaKeywords" : "", "name" : "", "unescapedHtmlTitle" : "", "unescapedMetaDescription" : null }) ``` | Variable | Type | Description | | --- | --- | --- | | `account` | Dict | This variable is a dictionary that stores company personalization properties for a known contact. Properties can be accessed from this dict, by adding a period and the property name. For example, `account.name` would print the company name of a contact._Use of this variable will disable page caching._ | | `company_domain` | String | Prints the company domain from **Website** **> Pages > Branding > Logo Link**. | | `contact` | Dict | This variable is a dictionary that stores contact personalization properties for a known contact. Properties can be accessed from this dict, by adding a period and the property name. For example, `contact.firstname` would print the first name of a contact._Use of this variable will disable page caching._ | | `content` | Dict | This variable is a dictionary that stores various properties pertaining to a specific piece of content such as an email, a page, or a post. | | `content.absolute_url` | String | Prints the full URL of a page, post, or web page version of an email. | | `content.archived` | Boolean | This variable evaluates to True, if the page or email was marked as archived by the user. | | `content.author_email` | String | The email address of the content creator. | | `content.author_name` | String | The first and last name of the content creator. | | `content.author_username` | String | The HubSpot username of the content creator. | | `content.campaign` | String | The GUID for the marketing campaign that this page or email is associated with. This unique ID can be found in the URL of a particular campaign in the Campaign's tool. | | `content.campaign_name` | String | The name of the marketing campaign that this page, this post, or this email is associated with. | | `content.created` | Datetime | A datetime object for when the content was originally created, in UTC time. This variable can be formatted with the [datetime filter](/reference/cms/hubl/filters#datetimeformat). | | `content.meta_description` | String | When pulling the meta description of a page, it is better to use the variable `page_meta.meta_description`. | | `content.name` | String | The name of a post, email, or page. For pages and emails this will print the internal content name, while for posts this will print the post title. For blog posts, this is the post title that displays. For other types of content, this is generally an internal name. This variable includes a wrapper so that it is editable via the UI, when included in blog posts. If you want to print the content name without a wrapper, use page_meta.name. | | `content.publish_date` | Datetime | A datetime object representing when the content was published, in UTC time. This variable can be formatted with the [format_datetime filter](/reference/cms/hubl/filters#format-datetime). | | `content.publish_date_localized` | String | A string representing the datetime when the content was published using the time zone defined in the account's [default settings](https://knowledge.hubspot.com/account/change-your-language-and-region-settings). This variable is also subject to the language and date format settings in **Settings > Website > Blog > Date Formats**. | | `content.template_path` | String | The Design Manager file path to your template (ie `custom/page/web_page_basic/my_template.html`). | | `content.slug` | String | The URL slug of a page, post, or web page version of an email. This is the value that follows the domain. For example, in `https://example.com/about-us`, the slug is `about-us`.For the full URL, use `content.absolute_url` instead. | | `content.updated` | Datetime | A datetime object for when the user last updated the content, in UTC time. This variable can be formatted with the datetime filter. _Does not equal_ `content.publish_date` _on initial publish. Use_ [\|between_times
](/reference/cms/hubl/filters#between-times) _filter to test if a post has been updated after publishing._ |
| `content_id` | String | Prints the unique ID for a page, post, or email. This ID can be found in the URL of the editor. You can use this variable as an alias for content.id. |
| `favicon_link` | String | Prints the source URL of the favicon. This image is set in **Settings > Website > Pages > Branding**. |
| `hub_id` | String | The portal ID of your HubSpot account. |
| `hubspot_analytics_tracking_code` | String | Includes the analytics tracking code. This tag is not necessary, because `standard_footer_includes`, already renders the tracking code. |
| `local_dt` | Datetime | A datetime object of the current time in the time zone defined in your Report Settings. _Usage of this variable will disable page caching in order to return the current time. May hurt page performance. Use JavaScript instead to get current date and time in a cacheable way._ |
| `local_time_zone` | String | The time zone, as configured in your HubSpot Report Settings. |
| `page_meta.canonical_url` | String | The official URL that this page should be accessed at. Usually does not include any query string parameters. Use this for the `rel="canonical"` tag. HubSpot automatically canonicalizes URLs. |
| `page_meta.html_title` | String | The title of the page. This variable should be used in the `Hi {{contact.firstname}},
\nDescribe what you have to offer the customer. Why should they read? What did you promise them in the subject line? Tell them something cool. Make them laugh. Make them cry. Well, maybe don't do that...
\nUse a list to:
\nLINK TO A LANDING PAGE ON YOUR SITE (This is the really important part.)
\nNow wrap it all up with a pithy little reminder of how much you love them.
\nAw. You silver-tongued devil, you.
\nSincerely,
\nYour name
``` ## Office location information Office location information footer for emails (CAN-SPAM compliant). ```hubl {% module "email_can_spam" path="@hubspot/email_can_spam" %} ``` | Parameter | Type | Description | | --- | --- | --- | | `html` | Rich Text | Populates required CAN-SPAM information for emails including business address and unsubscribe/preferences links.See below for this field's default value. | ```hubl ``` ## Email one line of text A version of the [text](#one-line-of-text) module for emails. ```hubl {% module "text" path="@hubspot/email_text" %} ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `value` | Text | Add your text to this parameter. | `"Some additional information in one line"` | ## Email section header A version of the [section header](#section-header) module for emails. ```hubl {% module "section_header" path="@hubspot/email_section_header" %} ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `header` | Text | Section header content. | `"A clear and bold header"` | | `heading_level` | Choice | Heading level for the `header`. Choices include `h1` through `h6`. | `h1` | | `subheader` | Text | Subheading paragraph text for the section. | `"A more subdued subheader"` | ## Email social sharing A version of the [social sharing](#social-sharing) module for emails. ```hubl {% module "social_sharing" path="@hubspot/email_social_sharing" %} ``` Note: The variable `social_link_url` in the default column below is the same value as the `link` parameter. | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `link` | Text | This is the destination link that will be shortened for easier sharing on social networks. | | | `facebook` | Object | Object containing:\{ "enabled": false, "custom_link_format": "https://twitter.com/intent/tweet?original_referer=\{\{ social_link_url }}&url=\{\{ social_link_url }}&source=tweetbutton&text=\{\{ social_page_title\|urlencode }}" }
|
| `linkedin` | Object | Object containing:Sorry. There were no results for [[search_term]].
Try rewording your query, or browse through our site.
" }, { "label": "First page link text", "name": "first_page_link_text", "type": "text", "default": "First Page" }, { "label": "Current page aria label", "name": "current_page_aria_label", "type": "text", "default": "Current Page" }, { "label": "Page number aria label", "name": "page_number_aria_label", "type": "text", "default": "Page" }, { "label": "Last page link text", "name": "last_page_link_text", "type": "text", "default": "Last Page" }, { "label": "Previous page link text", "name": "previous_page_link_text", "type": "text", "default": "Previous" }, { "label": "Next page link text", "name": "next_page_link_text", "type": "text", "default": "Next" } ], "locked": true }, { "label": "Styles", "name": "styles", "type": "group", "tab": "STYLE", "children": [ { "label": "Container", "name": "container", "type": "group", "children": [ { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Spacing", "name": "spacing", "type": "spacing" } ] } ] }, { "label": "Title", "name": "title", "type": "group", "visibility": { "operator": "EQUAL", "controlling_field": "title.show_title", "controlling_value_regex": "true" }, "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } }, { "label": "Transform", "name": "transform", "type": "choice", "choices": [ ["none", "None"], ["capitalize", "Capitalize"], ["uppercase", "Uppercase"], ["lowercase", "Lowercase"] ], "display": "select" } ] }, { "label": "Results count message", "name": "results_count_message", "type": "group", "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } }, { "label": "Transform", "name": "transform", "type": "choice", "choices": [ ["none", "None"], ["capitalize", "Capitalize"], ["uppercase", "Uppercase"], ["lowercase", "Lowercase"] ], "display": "select" } ] }, { "label": "Results", "name": "results", "type": "group", "children": [ { "label": "Image", "name": "featured_image", "type": "group", "visibility": { "controlling_field": "results.display_for_each_result", "controlling_value_regex": "image", "operator": "MATCHES_REGEX" }, "children": [ { "label": "Size", "name": "size", "type": "group", "children": [ { "label": "Aspect ratio", "name": "aspect_ratio", "type": "choice", "choices": [ ["1/1", "1:1"], ["3/2", "3:2"], ["2/3", "2:3"], ["4/3", "4:3"], ["3/4", "3:4"], ["16/9", "16:9"] ], "display": "select" }, { "label": "Width", "name": "width", "type": "number", "display": "text", "max": 75, "min": 25, "step": 5, "suffix": "%" } ] }, { "label": "Corner", "name": "corner", "type": "group", "children": [ { "label": "Radius", "name": "radius", "type": "number", "display": "text", "max": 100, "step": 1, "suffix": "px" } ] }, { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Spacing", "name": "spacing", "type": "spacing", "visibility": { "hidden_subfields": { "padding": true } } }, { "label": "Between image and content", "name": "between_image_and_content", "type": "number", "display": "text", "max": 50, "min": 0, "step": 1, "suffix": "px" } ] } ] }, { "label": "Title", "name": "title", "type": "group", "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } } ] }, { "label": "Preview text", "name": "description", "type": "group", "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } } ] }, { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Space between results", "name": "space_between_results", "type": "number", "display": "text", "max": 48, "min": 12, "step": 2, "suffix": "px" } ] } ] }, { "label": "Pagination", "name": "pagination", "type": "group", "children": [ { "label": "Numbers", "name": "numbers", "type": "group", "visibility": { "controlling_field": "pagination.numbers", "controlling_value_regex": "show_numbers", "operator": "MATCHES_REGEX" }, "children": [ { "label": "Text", "name": "text", "type": "group", "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } } ] }, { "label": "Background", "name": "background", "type": "group", "children": [ { "label": "Color", "name": "color", "type": "color" } ] }, { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Spacing", "name": "spacing", "type": "spacing", "visibility": { "hidden_subfields": { "margin": true } } } ] }, { "label": "Border", "name": "border", "type": "group", "children": [ { "label": "Border", "name": "border", "type": "border" } ] }, { "label": "Corner", "name": "corner", "type": "group", "children": [ { "label": "Radius", "name": "radius", "type": "number", "display": "text", "max": 100, "step": 1, "suffix": "px" } ] }, { "label": "Hover", "name": "hover", "type": "group", "children": [ { "label": "Text color", "name": "text_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } } }, { "label": "Background color", "name": "background_color", "type": "color" }, { "label": "Border color", "name": "border_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } } } ] }, { "label": "Active", "name": "active", "type": "group", "help_text": "Styles the numbered link matching the page that you're currently on.", "children": [ { "label": "Text color", "name": "text_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } } }, { "label": "Background color", "name": "background_color", "type": "color" }, { "label": "Border color", "name": "border_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } } } ] } ] }, { "label": "Previous and next", "name": "previous_and_next", "type": "group", "advanced_visibility": { "boolean_operator": "OR", "criteria": [ { "controlling_field": "previous_and_next", "controlling_value_regex": "show_arrows", "operator": "MATCHES_REGEX" }, { "controlling_field": "previous_and_next", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" } ] }, "children": [ { "label": "Text", "name": "text", "type": "group", "visibility": { "controlling_field": "previous_and_next", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" }, "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } } ] }, { "label": "Icon", "name": "icon", "type": "group", "visibility": { "controlling_field": "previous_and_next", "controlling_value_regex": "show_arrows", "operator": "MATCHES_REGEX" }, "children": [ { "label": "Size", "name": "size", "type": "number", "display": "text", "max": 100, "step": 1, "suffix": "px" } ] }, { "label": "Background", "name": "background", "type": "group", "children": [ { "label": "Color", "name": "color", "type": "color" } ] }, { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Space between text and icon", "name": "space_between_text_and_icon", "type": "number", "advanced_visibility": { "boolean_operator": "AND", "criteria": [ { "controlling_field": "previous_and_next", "controlling_value_regex": "show_arrows", "operator": "MATCHES_REGEX" }, { "controlling_field": "previous_and_next", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" } ] }, "display": "slider", "max": 25, "step": 1, "suffix": "px", "visibility_rules": "ADVANCED" }, { "label": "Spacing", "name": "spacing", "type": "spacing", "visibility": { "hidden_subfields": { "margin": true } } } ] }, { "label": "Border", "name": "border", "type": "group", "children": [ { "label": "Border", "name": "border", "type": "border" } ] }, { "label": "Corner", "name": "corner", "type": "group", "children": [ { "label": "Radius", "name": "radius", "type": "number", "display": "text", "max": 100, "step": 1, "suffix": "px" } ] }, { "label": "Hover", "name": "hover", "type": "group", "children": [ { "label": "Text color", "name": "text_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true }, "controlling_field": "previous_and_next", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" } }, { "label": "Background color", "name": "background_color", "type": "color" }, { "label": "Border color", "name": "border_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } } } ] } ], "visibility_rules": "ADVANCED" }, { "label": "First and last", "name": "first_and_last", "type": "group", "advanced_visibility": { "boolean_operator": "OR", "criteria": [ { "controlling_field": "first_and_last", "controlling_value_regex": "show_arrows", "operator": "MATCHES_REGEX" }, { "controlling_field": "first_and_last", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" } ] }, "children": [ { "label": "Text", "name": "text", "type": "group", "visibility": { "controlling_field": "first_and_last", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" }, "children": [ { "label": "Font", "name": "font", "type": "font", "default": { "size_unit": "px" } } ] }, { "label": "Icon", "name": "icon", "type": "group", "visibility": { "controlling_field": "first_and_last", "controlling_value_regex": "show_arrows", "operator": "MATCHES_REGEX" }, "children": [ { "label": "Size", "name": "size", "type": "number", "display": "text", "max": 100, "step": 1, "suffix": "px" } ] }, { "label": "Background", "name": "background", "type": "group", "children": [ { "label": "Color", "name": "color", "type": "color" } ] }, { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Space between text and icon", "name": "space_between_text_and_icon", "type": "number", "advanced_visibility": { "boolean_operator": "AND", "criteria": [ { "controlling_field": "first_and_last", "controlling_value_regex": "show_arrows", "operator": "MATCHES_REGEX" }, { "controlling_field": "first_and_last", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" } ] }, "display": "slider", "max": 25, "step": 1, "suffix": "px", "visibility_rules": "ADVANCED" }, { "label": "Spacing", "name": "spacing", "type": "spacing", "visibility": { "hidden_subfields": { "margin": true } } } ] }, { "label": "Border", "name": "border", "type": "group", "children": [ { "label": "Border", "name": "border", "type": "border" } ] }, { "label": "Corner", "name": "corner", "type": "group", "children": [ { "label": "Radius", "name": "radius", "type": "number", "display": "text", "max": 100, "step": 1, "suffix": "px" } ] }, { "label": "Hover", "name": "hover", "type": "group", "children": [ { "label": "Text color", "name": "text_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true }, "controlling_field": "first_and_last", "controlling_value_regex": "show_labels", "operator": "MATCHES_REGEX" } }, { "label": "Background color", "name": "background_color", "type": "color" }, { "label": "Border color", "name": "border_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } } } ] } ], "visibility_rules": "ADVANCED" }, { "label": "Spacing", "name": "spacing", "type": "group", "children": [ { "label": "Space between links", "name": "space_between_links", "type": "number", "display": "slider", "max": 50, "min": 0, "step": 5, "suffix": "px" }, { "label": "Spacing", "name": "spacing", "type": "spacing", "visibility": { "hidden_subfields": { "padding": true } } } ] } ] } ] } ] ``` ```html {% set heading_tag = module.heading_tag %} {% set searched_term = request.query_dict.term ? request.query_dict.term : request.query_dict.q %} {% set results_title = module.default_text.results_title %} {% set results_count_message = module.default_text.results_count_message %} {% if module.pagination.numbers.index("show_numbers") >= 0 %} {% set show_numbers = true %} {% endif %} {% if module.pagination.previous_and_next.index("show_labels") >= 0 %} {% set show_next_and_previous_labels = true %} {% endif %} {% if module.pagination.previous_and_next.index("show_arrows") >= 0 %} {% set show_next_and_previous_arrows = true %} {% endif %} {% if module.pagination.first_and_last.index("show_labels") >= 0 %} {% set show_first_and_last_labels = true %} {% endif %} {% if module.pagination.first_and_last.index("show_arrows") >= 0 %} {% set show_first_and_last_arrows = true %} {% endif %} {% if module.results.display_for_each_result.index("image") >= 0 %} {% set show_featured_images = true %} {% endif %} {# Module styles #} {% require_css %} {% end_require_css %} {% macro first_page_icon_markup() %} {% icon "first_icon" extra_classes="hs-search-results__pagination__link-icon", name="angle-double-left", purpose="decorative", style="SOLID", unicode="f100" %} {% endmacro %} {% macro previous_page_icon_markup() %} {% icon "previous_icon" extra_classes="hs-search-results__pagination__link-icon", name="angle-left", purpose="decorative", style="SOLID", unicode="f104" %} {% endmacro %} {% macro next_page_icon_markup() %} {% icon "next_icon" extra_classes="hs-search-results__pagination__link-icon", name="angle-right", purpose="decorative", style="SOLID", unicode="f105" %} {% endmacro %} {% macro last_page_icon_markup() %} {% icon "last_icon" extra_classes="hs-search-results__pagination__link-icon", name="angle-double-right", purpose="decorative", style="SOLID", unicode="f101" %} {% endmacro %} {% if module.title.show_title and ( request.query_dict.term or request.query_dict.q or is_in_editor ) %} {% if !heading_tag %} {% set heading_tag = 'h1' %} {% endif %} <{{ heading_tag }} class="hs-search-results-title">{{ results_title }}{{ heading_tag }}> {% endif %} {% endif %}Description
\{ "enabled": false, "custom_link_format": "https://twitter.com/intent/tweet?original_referer=\{\{ social_link_url }}&url=\{\{ social_link_url }}&source=tweetbutton&text=\{\{ social_page_title\|urlencode }}" }
|
| `linkedin` | Object | Object containing:This is the descriptive text contained in tab 1.
", "tab_label" : "Tab 1 label" }, { "content" : "This is the descriptive text contained in tab 2.
", "tab_label" : "Tab 2 label" } ], fixed_height=false %} ``` | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `tabs` | Field group | A field group that contains the tab label and text content of each tab. Contains the following fields:Add content here.
{% end_widget_attribute %} {% end_widget_block %} ``` ```html ``` ## content_attribute In addition to regular and block syntax, there are certain instances where you may want to specify a large block default content for a predefined content variable. The most common example of this proves to be the [content.email_body](/reference/cms/hubl/variables#email-variables) variable. This variable prints a standard email body that can be altered in the content editor. Since this isn't a standard HubL module, we use a **content_attribute** tag to specify a block of default content. The example below shows the email body variable populated with a default content code block. ```hubl {% content_attribute "email_body" %}Hi {{ contact.firstname }},
Describe what you have to offer the customer. Why should they read? What did you promise them in the subject line? Tell them something cool. Make them laugh. Make them cry. Well, maybe don't do that...
Use a list to:
LINK TO A LANDING PAGE ON YOUR SITE (This is the really important part.)
Now wrap it all up with a pithy little reminder of how much you love them.
Aw. You silver-tongued devil, you.
Sincerely,
Your name
{% end_content_attribute %} ``` ## Parameters available for all modules While some modules have certain [special parameters](/reference/cms/hubl/tags/standard-tags), below is a list of parameters supported by all modules. | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `label` | String | The name of the module displayed in the content editor. This parameter can also be used to give users additional instructions. | | | `overrideable` | Boolean | Controls whether or not the module can be edited in the content editor, equivalent to the _Prevent editing in content editors_ setting in the design manager. | `True` | | `no_wrapper` | Boolean | When set to `True`, removes the wrapping markup from around the content of a module.On pages, modules are always wrapped in a `Hello, world!
', }, ]; ``` | Prop | Type | Description | | --- | --- | --- | | `fieldPath` | String | The field of the Rich Text field to render. | | `tag` | String | The HTML tag used as the wrapping element for the content (e.g., `div`). | # @ Learn more about CMS React module field types. $ reference & cms/react --- # Field types When building CMS React modules, you'll use fields to define the customizable elements of a module, such as rich text fields and image fields. These fields are the same [fields provided for HubL modules](/reference/cms/fields/module-theme-fields), though their [implementation](/guides/cms/react/modules#module-fields) is slightly different. Field types for CMS React modules also include TypeScript definitions, so you'll benefit from autocompletion and validation when defining the fields. View reference documentation for all [available field types on GitHub](https://github.hubspot.com/cms-react/field-types/). ```js import { ModuleFields, TextField, RichTextField, ImageField, } from '@hubspot/cms-components/fields'; import { RichText } from '@hubspot/cms-components'; import logo from '../../../assets/sprocket.svg'; import styles from '../../../styles/getting-started.module.css'; export function Component({ fieldValues, hublParameters }) { const { src, alt, width, height } = fieldValues.logo; const { brandColors } = hublParameters; return (
|
toggleType='checkboxList' (default)
|
|
toggleType='radioButtonList'
|
|
inline={true}
|
Send an email to thank them for their time and follow up. Use one of our templates based on the call outcome.
", "createdAt": "2024-06-26T18:37:01.146Z", "updatedAt": "2024-06-26T18:37:01.146Z" } }, { "id": "198771537", "stepOrder": 2, "delayMillis": 0, "actionType": "FINISH_ENROLLMENT", "createdAt": "2024-06-26T18:37:01.146Z", "updatedAt": "2024-06-26T18:37:01.146Z" } ], "settings": { "id": "18167737", "eligibleFollowUpDays": "BUSINESS_DAYS", "sellingStrategy": "LEAD_BASED", "sendWindowStartMinute": 480, "sendWindowEndMinute": 1080, "taskReminderMinute": 480, "individualTaskRemindersEnabled": false, "createdAt": "2024-06-26T18:37:01.146Z", "updatedAt": "2024-06-26T18:37:01.146Z" }, "dependencies": [ { "id": "15241774", "createdAt": "2024-06-26T18:37:01.146Z", "updatedAt": "2024-06-26T18:37:01.146Z", "dependencyType": "TASK_COMPLETION", "requiredBySequenceStepId": "198771536", "reliesOnSequenceStepId": "198771535", "requiredByStepOrder": 1, "reliesOnStepOrder": 0 }, { "id": "15241775", "createdAt": "2024-06-26T18:37:01.146Z", "updatedAt": "2024-06-26T18:37:01.146Z", "dependencyType": "TASK_COMPLETION", "requiredBySequenceStepId": "198771537", "reliesOnSequenceStepId": "198771536", "requiredByStepOrder": 2, "reliesOnStepOrder": 1 } ] } ``` The details of each response field are outlined in the table below: | Field | Type | Description | | --- | --- | --- | | id | String | The sequence ID. | | name | String | The name of the sequence. | | steps | Array | The list of steps in your sequence. Each step is an object that includes details like the type, priority, and creation details. | ## List sequences To get details about a specific sequence in your account, make a `GET` request to `/automation/v4/sequences/?limit=#&userId={userId}`. Use the amount of sequences you want returned as the limit in the request URL and use your [userID](/guides/api/settings/users/user-details) as a query parameter. For example, to get a list of four sequences and your user ID is `2222222`, make a `GET` request to `/automation/v4/sequences?limit=4&userId=2222222`. The response for fetching a list of sequences would resemble the following: ```json //Example response for GET request to https://api.hubapi.com/automation/v4/sequences?limit=4&userId={userId} { "total": 7, "results": [ { "id": "88180366", "name": "Melinda's call sequence", "createdAt": "2023-07-20T15:40:04.364Z", "updatedAt": "2023-07-20T15:40:04.364Z", "userId": "2222222" }, { "id": "76853632", "name": "Melinda's Follow-up Sequence", "createdAt": "2023-01-26T15:38:05.812Z", "updatedAt": "2023-01-27T16:06:12.562Z", "userId": "2222222" }, { "id": "76897322", "name": "Melinda's Marketing Pro Demo Sequence", "createdAt": "2023-01-27T16:42:29.487Z", "updatedAt": "2023-05-03T14:40:42.507Z", "userId": "2222222" }, { "id": "76849666", "folderId": "67555200", "name": "Melinda's Sales Sequence", "createdAt": "2023-01-26T15:26:56.574Z", "updatedAt": "2023-05-26T17:16:57.866Z", "userId": "2222222" } ], "paging": { "next": { "after": "NA%3D%3D", "link": "https://api.hubspot.com/automation/v4/sequences/?limit=4&userId=8698664&portalId=6331522&hs_static_app=api-goggles&hs_static_app_version=1.7830&after=NA%3D%3D" } } } ``` The details of each response field are outlined in the table below: | Field | Type | Description | | --------- | ------ | ----------------------------------------------------- | | total | String | The number of sequences in your account. | | id | String | The sequence ID. | | name | String | The name of the sequence. | | createdAt | String | The time the sequence was created in UTC format. | | updatedAt | String | The time the sequence was last updated in UTC format. | | userID | String | The userID of the user who created the sequence. | ## Enroll a contact in a sequence To enroll a contact in a sequence, make a `POST` request to `/automation/v4/sequences/enrollments/`. Use your [user ID](/guides/api/settings/users/user-details) as the query parameter. Specify the sequenceId, contactId, and senderEmail in the body. The senderEmail must be an email address that's [connected](https://knowledge.hubspot.com/connected-email/connect-your-inbox-to-hubspot) to your HubSpot account. For example, to enroll a contact whose ID is `33333` in sequence that’s ID is `44444444`, you’d make a `POST` request to `/automation/v4/sequences/enrollments`. The body would resemble the following: ```json // Example of request body for POST request { "sequenceId": "33333", "contactId": "44444444", "senderEmail": "menelson@hubspot.com" } ``` The response for enrolling a contact in a sequence would resemble the following: ```json // Example response for POST request to https://api.hubapi.com//automation/v4/sequences/enrollments/ { "id": "2435404604", "toEmail": "RachelGreen.com", "enrolledAt": "2024-06-27T20:11:02.824Z", "updatedAt": "2024-06-27T20:11:02.824Z" } ``` The details of each response field are outlined in the table below: | Field | Type | Description | | --- | --- | --- | | id | String | The ID for the enrollment object. | | toEmail | String | The email of the contact | | enrolledAt | String | The time the contact was enrolled in the sequence in UTC format. | | updatedAt | String | The last time the enrollment was updated (paused, unpaused, etc.) | There is a limit of 1000 enrollments per portal inbox per day. ## View a contact's sequence enrollment status A contact's enrollment status will indicate if the contact is enrolled in any sequences at the time of the request. To get a contact's enrollment status, make a `GET` request to /`automation/v4/sequences/enrollments/contact/{contactId}`. For example, to view the enrollment status of a contact whose contact ID is `33333`, make a `GET` request to `/automation/v4/sequences/enrollments/contact/33333`. Use the contact ID as the query parameter. The response for viewing a contact's sequence enrollment status would resemble the following: ```json // Example response for GET request to https://api.hubapi.com/automation/v4/enrollments/contact/{contactId} { "id": "2435404604", "toEmail": "RachelGreen@gmail.com", "enrolledAt": "2024-06-27T20:11:02.824Z", "updatedAt": "2024-06-27T20:11:02.824Z", "sequenceId": "76853632", "sequenceName": "Melinda's Sales Hub Sequence" "enrolledBy": "8698664", "enrolledByEmail": "menelson@hubspot.com" } ``` The details of each response field are outlined in the table below: | Field | Type | Description | | --- | --- | --- | | id | String | The ID for the enrollment object. | | toEmail | String | The email of the contact | | enrolledAt | String | The time the contact was enrolled in the sequence in UTC format. | | updatedAt | String | The last time the enrollment was updated (paused, unpaused, etc.) | | sequenceID | String | The ID of the sequence the contact is enrolled in. | | sequenceName | String | The title of the sequence the contact is enrolled in. | | enrolledBy | String | The userId of the user who enrolled the contact in the sequence. | | enrolledByEmail | String | The email of the user who enrolled the contact in the sequence or the email address that email messages are sent from. | # Automation API | Automation v4 API (BETA) @ Learn how to use the v4 automation API (BETA). $ guides & api/automation --- # Automation v4 API (BETA) You can use the automation v4 API to fetch data from existing [workflows](https://knowledge.hubspot.com/workflows/create-workflows), create new workflows, as well as delete workflows you no longer need. The sections below provide a walkthrough of how to use the v4 endpoints. For a full reference of the available endpoints and their required fields, check out the [endpoint reference documentation](/reference/api/automation/create-manage-workflows). This API is currently in beta and is subject to change based on testing and feedback. By using these endpoints you agree to adhere to HubSpot's [Developer Terms](https://legal.hubspot.com/hs-developer-terms)& [Developer Beta Terms](https://legal.hubspot.com/hubspot-beta-terms). You also acknowledge and understand the risk associated with testing an unstable API. ## Scope requirements To use any of the v4 endpoints, your app will need to be authorized to use the `automation` scope. In addition, if you need to access sensitive data properties in a workflow, enroll records in a workflow that references sensitive data, or retrieve enrollment and performance data for workflows with sensitive data properties, you'll need to authorize sensitive data scopes that are detailed in the sections below. Learn more about working with sensitive data in the [HubSpot Knowledge Base](https://knowledge.hubspot.com/properties/store-sensitive-data). ### Retrieving workflows that reference sensitive data To retrieve enrollment data and performance stats for existing workflows that reference sensitive data properties, your app will need to request and be granted one of the scopes below, based on the enrolled record type in your workflow: - `crm.objects.contacts.sensitive.read`: view enrollment and performance data for existing contact-based workflows. - `crm.objects.companies.sensitive.read`: view enrollment and performance data for existing company-based workflows. - `crm.objects.deals.sensitive.read`: view enrollment and performance data for existing deal-based workflows. - `crm.objects.custom.sensitive.read`: view enrollment and performance data for workflows based on custom objects an account. The scopes above are not sufficient to create or delete workflows using the v4 API, nor enroll records in existing workflows that access sensitive data properties. Consult the sensitive data write scopes in the section below if you need to perform these operations via the v4 API. ### Creating and managing workflows that reference sensitive data To create or delete workflows that reference sensitive data, or enroll records in an existing workflow, your app will need to request and be granted one of the scopes below, based on the enrolled record type of your workflow: - `crm.objects.contacts.sensitive.write`: create and delete contact-based workflows via the v4 API, as well as enroll contacts in existing workflows that access sensitive data. - `crm.objects.companies.sensitive.write`: create and delete company-based workflows via the v4 API, as well as enroll companies in existing workflows that access sensitive data. - `crm.objects.deals.sensitive.write`: create and delete deal-based workflows via the v4 API, as well as enroll deals in existing workflows that access sensitive data. - `crm.objects.custom.sensitive.write`: create and delete workflows based on custom objects via the v4 API, as well as enroll custom object records in existing workflows that access sensitive data. ## Fetch workflows The sections below detail how to fetch details about specific workflows, or getting details about multiple workflows in a single call. ### Fetch a specific workflow by ID To fetch data from an existing workflow, make a `GET` request to `/automation/v4/flows/{flowId}`, where `flowId` is the ID an existing workflow in your account. For example, if you made a `GET` request to `/automation/v4/flows/585051946` to get the workflow with an ID of `585051946`, the resulting response would be: ```json // Example workflow response from GET request to /automations/v4/flows/585051946 { "id": "585051946", "isEnabled": true, "flowType": "WORKFLOW", "revisionId": "7", "name": "New form submission workflow", "createdAt": "2024-06-07T17:27:08.101Z", "updatedAt": "2024-06-07T17:31:11.263Z", "startActionId": "1", "nextAvailableActionId": "3", "actions": [ { "type": "SINGLE_CONNECTION", "actionId": "1", "actionTypeVersion": 0, "actionTypeId": "0-13", "connection": { "edgeType": "STANDARD", "nextActionId": "2" }, "fields": { "operation": "ADD", "list_id": "178" } }, { "type": "SINGLE_CONNECTION", "actionId": "2", "actionTypeVersion": 0, "actionTypeId": "0-9", "fields": { "user_ids": ["2620022"], "delivery_method": "APP", "subject": "New form submission", "body": "Check out the new form submission we received!" } } ], "enrollmentCriteria": { "shouldReEnroll": false, "type": "EVENT_BASED", "eventFilterBranches": [ { "filterBranches": [], "filters": [], "eventTypeId": "4-1639801", "operator": "HAS_COMPLETED", "filterBranchType": "UNIFIED_EVENTS", "filterBranchOperator": "AND" } ], "listMembershipFilterBranches": [] }, "timeWindows": [], "blockedDates": [], "customProperties": {}, "crmObjectCreationStatus": "COMPLETE", "type": "CONTACT_FLOW", "objectTypeId": "0-1", "suppressionListIds": [], "canEnrollFromSalesforce": false } ``` The response above includes the specification for a contact-based workflow with two actions, and contacts are enrolled if they filled out a form on your website. ### Fetch workflows in bulk using their IDs To fetch multiple workflows using their IDs, you can make a `POST` request to the `/automation/v4/flows/batch/read` endpoint, and provide the ID of each workflow as the `flowId`, along with a `type` of `"FLOW_ID"` within an `inputs` array provided in the request body. For example, the request body below would fetch the workflow details for two workflows with IDs of `"619727002"` and `"617969780"`: ```json // Example request body for POST request to /automation/v4/flows/batch/read { "inputs": [ { "flowId": "619727002", "type": "FLOW_ID" }, { "flowId": "617969780", "type": "FLOW_ID" } ] } ``` ### Fetch all workflows To fetch all workflows, you can make a `GET` request to `/automation/v4/flows`. Keep in mind that the response will only include key fields for the workflow, such as `id`, `isEnabled`, `objectTypeId`, and the latest `revisionId`. If you want to get a full list of properties for a specific workflow, make a `GET` request to `/automation/v4/flows/{flowId}` and provide the specific ID of the workflow as the `flowId`. You can consult the sections below on how `actions` and enrollmentCriteria for a workflow are specified. Once you review these specifications, you can follow the steps in the [_Create a workflow_](#create-a-workflow) section to define and create a workflow using the v4 API. ## Action types Each workflow specification consists of a list of actions. Each action contains a set of required properties: - `actionId`: a unique ID that identifies this action, provided as a string. - `actionTypeId`: a predefined value that specifies the action type (e.g., `"0-1"` designates a `DELAY` action). A full list of actions and their associated `actionTypeId` is provided in the section below. - `actionTypeVersion`: a number that designates the version of the action. For all built-in action types (e.g., a delay, email notification, etc.), the `actionTypeVersion` will be `0`. - `connection`: for non-branching actions, this property is an object that specifies the subsequent action, and contains two nested properties: - `edgeType`: to proceed directly to the next action, this property should be set to `"STANDARD"`. If you have a branch in your workflow, you can go to an action in a different branch by setting the `edgeType` to `"GO-TO"`. - `nextActionId`: the ID of the subsequent action in the workflow. - `type`: for non-branching actions, this should be set to `SINGLE_CONNECTION`. - `fields`: an object that specifies the data required by the action (e.g., how long to delay an enrolled object for a `DELAY` action). The structure of this property depends on the action type. Consult the sections and example actions below for the fields each action type expects. ### Action type IDs The table below details the available action types along with the associated `actionTypeId`: | Action | Action type ID | Description | | --- | --- | --- | | Delay until a specific date or date-based property | `0-35` | Delay until a preconfigured calendar date or date property of the enrolled record. | | Delay a set amount of time, until a specific day of the week, or time of day. | `0-1` | Delay for a preconfigured amount of time (e.g., 3 hours, 5 days, etc.), until a specific day (e.g., Tuesday), or time of day (12:00 AM EST). | | Send automated email to a contact associated with the enrolled record | `0-4` | Send an automated marketing email to the enrolled record. | | Send email notification to a user or team | `0-8` | Send an internal email notification to a user or team in your account. | | Send an in-app notification to a user or team | `0-9` | Trigger an in-app notification to a user or team in your account. | | Set property | `0-5` | Set a property on an enrolled object. | | Create task | `0-3` | Create a new task. | | Create a new record | `0-14` | Create a new record (contact, company, deal, ticket, or lead). | | Add enrolled object to list | `0-63809083` | Add an enrolled contact to a static list. | | Remove enrolled object from list | `0-63863438` | Remove an enrolled contact from a static list. | ### Action fields The `fields` property of your action depends on the corresponding action type. - The actions available depend on your account subscription. Learn about all available actions in [this knowledge base article](https://knowledge.hubspot.com/workflows/choose-your-workflow-actions). - To confirm the fields required for a specific action, you can [create the workflow](https://knowledge.hubspot.com/workflows/create-workflows) with that action using the workflows tool, then make a `GET` request to `/automations/v4/flows/{flowId}` for that workflow. You can find the `flowId` of the workflow by editing the workflow then checking the URL for the second ID in the URL path, or you can make a `GET` request to `/automations/v4/flows` to get all workflows and filter the resulting response by the name of your workflow. The sections below outline the required fields for common actions in a workflow. ### Delay until a specific date or date-based property The code below specifies an example delay action until a specific date. Based on whether you're delaying until a preconfigured date or a date-based property of the enrolled record, you'll need to specify the sub-properties of the `date` field accordingly: - If you're delaying until a specific calendar date, provide `STATIC_VALUE` for the `type` sub-property, then provide the calendar date for the `staticValue` sub-property as a unix timestamp. - To delay until a date-based property of the enrolled record, provide `OBJECT_PROPERTY` for the `type` sub-property, then specify the property to use as the `propertyName`. ```json // Example of a delay action to delay until a specific date or date-based property { "type": "SINGLE_CONNECTION", "actionId": "5", "actionTypeVersion": 0, "actionTypeId": "0-35", "connection": { "edgeType": "STANDARD", "nextActionId": "7" }, "fields": { "date": { "type": "STATIC_VALUE", "staticValue": "1719446400000" }, "delta": "0", "time_unit": "DAYS", "time_of_day": { "hour": 12, "minute": 0 } } } ``` ### Delay a set amount of time The code below specifies an example delay action for a preconfigured amount of time. ```json // Example of a delay action to delay for a specific amount of time (e.g., 6 hours) { "type": "SINGLE_CONNECTION", "actionId": "5", "actionTypeVersion": 0, "actionTypeId": "0-35", "connection": { "edgeType": "STANDARD", "nextActionId": "7" }, "fields": { "delta": "720", "time_unit": "MINUTES" } } ``` ### Send an automated marketing email to an enrolled contact The following example action demonstrates how to send an automated marketing email with an ID of `113782603056` to an enrolled contact. ```json // Example action to send an automated marketing email to an enrolled contact { "type": "SINGLE_CONNECTION", "actionId": "4", "actionTypeVersion": 0, "actionTypeId": "0-4", "fields": { "content_id": "113782603056" } } ``` ### Set property The action definition below provides an example of setting the `hs_lead_status` property to `"IN_PROGRESS"`. ```json // Example action to set the hs_lead_status property to IN_PROGRESS { "actionId": "2", "actionTypeVersion": 0, "actionTypeId": "0-5", "connection": { "edgeType": "STANDARD", "nextActionId": "4" }, "fields": { "property_name": "hs_lead_status", "association": { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 1 }, "value": { "staticValue": "IN_PROGRESS" } } } ``` ### Create task The action definition below is an example of creating an unassigned task: ```json // Example action definition for creating a new unassigned task { "type": "SINGLE_CONNECTION", "actionId": "1", "actionTypeVersion": 0, "actionTypeId": "0-3", "fields": { "task_type": "TODO", "subject": "Check in with lead", "body": "Remember to sync up with new lead!
", "associations": [ { "target": { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 10 }, "value": { "type": "ENROLLED_OBJECT" } } ], "use_explicit_associations": "true", "priority": "NONE" } } ``` ### Create a new record The example action below creates a new deal and associates it with the contact enrolled in the workflow: ```json // Example action definition for creating a new deal and associating it with the enrolled contact { "type": "SINGLE_CONNECTION", "actionId": "2", "actionTypeVersion": 0, "actionTypeId": "0-14", "connection": { "edgeType": "STANDARD", "nextActionId": "3" }, "fields": { "object_type_id": "0-3", "properties": [ { "targetProperty": "dealstage", "value": { "type": "STATIC_VALUE", "staticValue": "appointmentscheduled" } }, { "targetProperty": "dealname", "value": { "type": "STATIC_VALUE", "staticValue": "New deal" } }, { "targetProperty": "amount", "value": { "type": "STATIC_VALUE", "staticValue": "1000" } } ], "associations": [ { "target": { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 3 }, "value": { "type": "ENROLLED_OBJECT" } } ], "use_explicit_associations": "true" } } ``` ### Add an enrolled object to a static list The following action definition is an example of adding an enrolled contact to a static list, specified as the `listId`. ```json // Example action to add an enrolled contact to a list { "actionId": "3", "actionTypeVersion": 0, "actionTypeId": "0-63809083", "fields": { "listId": "123" }, "type": "SINGLE_CONNECTION" } ``` ### Remove an enrolled object from a static list The following action definition is an example of removing an enrolled contact from a static list, specified as the `listId`. ```json // Example action to remove an enrolled contact from a list { "actionId": "3", "actionTypeVersion": 0, "actionTypeId": "0-63863438", "fields": { "listId": "123" }, "type": "SINGLE_CONNECTION" } ``` ### Branching actions Branching actions differ from other actions in that they don't follow the standard action structure. Branching action definitions don't have `fields` or `connection` properties. There are two types of branching actions: list branch actions and static branch actions. Both types must also define a default branch using the `defaultBranchName` and `defaultBranch` properties. #### List branch actions List branch actions include a `listBranches` property that specifies a set of filter branches to segment enrolled objects. Each `filterBranch` is configured using the syntax and formatting outlined in the [list filters documentation](/guides/api/crm/lists/lists-filters). ```json // Example list branch action { "actionId": "6", "listBranches": [ { "filterBranch": {}, "connection": { "edgeType": "STANDARD", "nextActionId": "7" } }, { "filterBranch": {}, "branchName": "Some branch name", "connection": { "edgeType": "GOTO", "nextActionId": "4" } } ], "defaultBranchName": "Fall-through branch", "defaultBranch": { "edgeType": "STANDARD", "nextActionId": "8" } } ``` #### Static branch actions Static branch actions include an `inputValue` definition, which supports different shapes for the input values of the branch. It also includes a list of `staticBranches`, which defines which actions come next in the branch. ```json // Example static branch action { "actionId": "1", "inputValue": { "propertyName": "example_property" }, "staticBranches": [ { "branchValue": "example_value_1", "connection": { "edgeType": "STANDARD", "nextActionId": "2" } }, { "branchValue": "example_value_1", "connection": { "edgeType": "STANDARD", "nextActionId": "3" } } // ... ], "defaultBranchName": "Fall-through branch", "defaultBranch": { "edgeType": "STANDARD", "nextActionId": "4" } } ``` ## Enrollment criteria You can configure the conditions for objects to be enrolled in your workflow within the `enrollmentCriteria` property of your workflow specification. - The data you specify varies based on whether your enrollment is event-based or list-based. You can specify the enrollment type by setting the `type` of `enrollmentCriteria` to either `EVENT_BASED` or `LIST_BASED`. - You can specify the re-enrollment settings for objects enrolled in your workflow by setting the `shouldReEnroll` field to `true` or `false`. Learn more about workflow enrollment in this [knowledge base article](https://knowledge.hubspot.com/workflows/set-your-workflow-enrollment-triggers). ### Event-based enrollment Event-based workflows will enroll objects when specific events occur, such as when a form is submitted. - You can configure the criteria for which events will trigger enrollment by defining a list of `eventFilterBranches`. Each `eventFilterBranch` definition specifies a qualifying event (e.g., a form submission) using an `eventTypeId` that corresponds to that event. - Most events will have the same values for the following fields: - `operator`: `"HAS_COMPLETED"` - `filterBranchType`: `"UNIFIED_EVENTS"` - `filterBranchOperator`: `"AND"` The table below defines each `eventTypeId` that corresponds to the event you can configure for your workflow: | Event | Event type ID | | ---------------------------- | ------------- | | Ad interaction | `4-1553675` | | Email open | `4-666440` | | Email reply | `4-665538` | | Email click | `4-666288` | | Email delivery | `4-665536` | | Form submission | `4-1639801` | | Form view | `4-1639797` | | Form interaction | `4-1639799` | | Marketing event registration | `4-68559` | | Marketing event cancellation | `4-69072` | | Call start | `4-1733817` | | Call end | `4-1741072` | | SMS shortlink click | `4-1722276` | | CTA view | `4-1555804` | | CTA click | `4-1555805` | | Media play on webpage | `4-675783` | The example code below defines the `enrollmentCriteria` to enroll contacts who successfully submitted a form: ```json // Example of an enrollmentCriteria definition to enroll contacts who submitted a form "enrollmentCriteria": { "shouldReEnroll": true, "type": "EVENT_BASED", "eventFilterBranches": [ { "filterBranches": [], "filters": [], "eventTypeId": "4-1639801", "operator": "HAS_COMPLETED", "filterBranchType": "UNIFIED_EVENTS", "filterBranchOperator": "AND" } ], "listMembershipFilterBranches": [] } ``` ### Filter-based enrollment Workflows with filter-based enrollment will enroll objects when the criteria you configure is met. - Criteria is configured setting the `listFilterBranch` field of your `enrollmentCriteria` based which objects should qualify for enrollment in your workflow. Within a listFilterBranch, you can define the specific filter criteria using a list of `filterBranches`. - You can learn more about the syntax and formatting for defining a `listFilterBranch` in the [list filters documentation](/guides/api/crm/lists/lists-filters). For example, the `enrollmentCriteria` below defines the criteria for when a contact's _City_ property is equal to _Dublin_: ```json // Example of an enrollmentCriteria definition to filter contacts based on whether their city property is equal to 'Dublin' "enrollmentCriteria": { "shouldReEnroll": false, "type": "LIST_BASED", "listFilterBranch": { "filterBranches": [ { "filterBranches": [], "filters": [ { "property": "city", "operation": { "operator": "IS_EQUAL_TO", "includeObjectsWithNoValueSet": false, "values": [ "Dublin" ], "operationType": "MULTISTRING" }, "filterType": "PROPERTY" } ], "filterBranchType": "AND", "filterBranchOperator": "AND" } ], "filters": [], "filterBranchType": "OR", "filterBranchOperator": "OR" }, "unEnrollObjectsNotMeetingCriteria": false, "reEnrollmentTriggersFilterBranches": [] } ``` ## Create a workflow To create a workflow, make a `POST` request to `/automations/v4/flows` and provide a workflow specification in the body of your request. - Consult the _Action types_ and _Enrollment criteria_ sections above for a full reference on specifying the `actions` in your workflow and configuring the `enrollmentCriteria`. - For contact-based workflows, set the `type` to `"CONTACT_FLOW"`. For all other workflow types (e.g., deal-based, goal-based, etc.), set the `type` to `"PLATFORM_FLOW"`. For example, if you wanted to create a workflow that executed the following: - Once a contact submits a specific form on your website, a ticket will be created in your account. - After a 1 day delay, the enrolled contact will be sent an [automated marketing email](https://knowledge.hubspot.com/marketing-email/create-automated-emails-to-use-in-workflows). The request body of your `POST` request would resemble the following: ```json // Example request body for POST request to create a workflow { "isEnabled": true, "flowType": "WORKFLOW", "name": "New form submission from interested contact", "startActionId": "1", "nextAvailableActionId": "4", "actions": [ { "type": "SINGLE_CONNECTION", "actionId": "1", "actionTypeVersion": 0, "actionTypeId": "0-14", "connection": { "edgeType": "STANDARD", "nextActionId": "3" }, "fields": { "object_type_id": "0-5", "properties": [ { "targetProperty": "subject", "value": { "type": "STATIC_VALUE", "staticValue": "Review new form submission" } }, { "targetProperty": "hs_pipeline_stage", "value": { "type": "STATIC_VALUE", "staticValue": "1" } }, { "targetProperty": "source_type", "value": { "type": "STATIC_VALUE", "staticValue": "FORM" } }, { "targetProperty": "content", "value": { "type": "STATIC_VALUE", "staticValue": "[Triage required] new form submitted. Next available rep should review." } } ], "associations": [ { "target": { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 16 }, "value": { "type": "ENROLLED_OBJECT" } }, { "target": { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 339 }, "value": { "type": "COPY_ASSOCIATION", "sourceSpec": { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 279 } } } ], "use_explicit_associations": "true" } }, { "type": "SINGLE_CONNECTION", "actionId": "2", "actionTypeVersion": 0, "actionTypeId": "0-4", "fields": { "content_id": "113782603056" } }, { "type": "SINGLE_CONNECTION", "actionId": "3", "actionTypeVersion": 0, "actionTypeId": "0-1", "connection": { "edgeType": "STANDARD", "nextActionId": "2" }, "fields": { "delta": "1440", "time_unit": "MINUTES" } } ], "enrollmentCriteria": { "shouldReEnroll": false, "type": "EVENT_BASED", "eventFilterBranches": [ { "filterBranches": [], "filters": [ { "property": "hs_form_id", "operation": { "operator": "IS_ANY_OF", "includeObjectsWithNoValueSet": false, "values": ["2f5cc7f8-d359-4e9c-a770-dd42ea07d217"], "operationType": "ENUMERATION" }, "filterType": "PROPERTY" } ], "eventTypeId": "4-1639801", "operator": "HAS_COMPLETED", "filterBranchType": "UNIFIED_EVENTS", "filterBranchOperator": "AND" } ], "listMembershipFilterBranches": [] }, "timeWindows": [], "blockedDates": [], "customProperties": {}, "crmObjectCreationStatus": "COMPLETE", "type": "CONTACT_FLOW", "objectTypeId": "0-1", "suppressionListIds": [], "canEnrollFromSalesforce": false } ``` ## Update a workflow To update an existing workflow, make a PUT request to `/automation/v4/{flowId}` using the ID of your workflow you want to update as the flowId, and providing any properties you want to change in the request body. - You must include the `revisionId` and `type` properties in your request body. - The `revisionId` must correspond to the most current revision of your workflow, which you can retrieve by making a `GET` request to `/automation/v4/{flowId}`. For the example, to enable a workflow that's currently turned off, the request body below would enable the workflow, using its most recent revisionId of `"5"`: ```json // Example request body for PUT request to update a workflow { "isEnabled": true, "revisionId": "5", "type": "CONTACT_FLOW" } ``` ## Delete a workflow To delete a workflow, make a `DELETE` request to `/automations/v4/{flowId}` using the ID of the workflow you want to delete as the `flowId`. Once deleted, you cannot restore the workflow via the automation API. You must [contact HubSpot Support](https://knowledge.hubspot.com/help-and-resources/get-help-with-hubspot) to get assistance with restoring your workflow. # CMS API | Blog Authors @ The blog authors endpoints are used to create and manage hubspot blog authors $ guides & api/cms/blogs --- Use the blog authors API to manage author information for your blog posts. Learn more about how to create and maintain your blog on the [HubSpot Knowledge Base.](https://knowledge.hubspot.com/website/topics#blog) ## Changes in V3 The following properties are deprecated and will not be included in the response of any of the V3 endpoints: - `user_id` - `username` - `googlePlus` - `gravatarUrl` - `twitterUsername` - `hasSocialProfiles` ## Search blog authors To retrieve an account's blog authors, make a `GET` request to `/cms/v3/blogs/authors`. You can filter and sort the authors returned in the response using the operators and properties described below. You can also use the standard filters using the _createdAt_ and _updatedAt_ dates. ### Filtering Provide any filters as query parameters in your request, by adding the **property name**, followed by **two underscore characters**, then include the associated **operator** as a suffix. For example, you can filter the results to only include authors where the `displayName` property contains the word _J\_\_ohn_ using the parameter: `&displayName__icontains=john`. You can include any number of filters as query parameters in the request URL. All filters are ANDed together. ORing filters is not currently supported. The available filter types are listed below: | Operator | Description | | ------------ | ------------------------- | | `eq` | Equal to | | `ne` | Not equal to | | `contains` | Contains | | `lt` | Less than | | `lte` | Less than or equal to | | `gt` | Greater than | | `gte` | Greater than or equal to | | `is_null` | Null | | `not_null` | Not null | | `like` | Is like | | `not_like` | Not like | | `icontains` | Contains (case sensitive) | | `startswith` | Starts with | | `in` | In | The table below lists the properties that can be filtered on, along with their supported filter types. | Operator | Description | | ------------------ | ------------------------------ | | `id` | `eq`, `in`, `not_in` | | `fullName` | `eq`, `in`, `contains` | | `email` | `eq`, `ne`, `not_null` | | `slug` | `eq` | | `createdAt` | `eq`, `gt`, `gte`, `lt`, `lte` | | `updatedAt` | `eq`, `gt`, `gte`, `lt`, `lte` | | `name` | `eq`, `in`, `contains` | | `deletedAt` | `eq`, `gt`, `gte`, `lt`, `lte` | | `createdById` | `eq` | | `updatedById` | `eq` | | `language` | `in`, `not_null` | | `translatedFromId` | `null`, `not_null` | To filter blog authors based on a multi-language group, you can include one of the query parameters in the table below. For example, to get blog authors associated with the German variation of your blog, you'd include `language_in=de` as a query parameter. | Parameter | Description | | --- | --- | | `translatedFromId__is_null` | Primary blog author in a multi-language group. | | `translatedFromId__not_null` | Variation blog author in a multi-language group. | | `language__in` | Blog author with a specific language. | ### Sorting and paginating You can provide sorting and pagination options as query parameters. Specify the **property name** as the value to the sort query parameter to return the blog authors in the natural order of that property. You can reverse the sorting order by including a dash character before the property name (e.g., `sort=-createdAt`). By combining query parameters for filtering, sorting, and paging, you can retrieve blog authors that match more advanced search criteria. For example, the request below fetches blog authors that don't have a language assigned, ordered by the most recently updated. The limit and offset parameters below return the second page of results. ```shell curl https://api.hubapi.com/cms/v3/blogs/authors?sort=-updatedAt&&language__not_null&limit=10&offset=10 \ --request POST \ --header "Content-Type: application/json" ``` ## Create blog authors To create a blog author, make a `POST` request to `/cms/v3/blogs/authors`, and include a JSON payload that represents the blog author model. The `fullName` field is required when creating a blog author. To set the URL of a blog author profile page, you must provide the `slug` field in your request. Review the required parameters and the structure of the blog author model in the [reference documentation](https://developers.hubspot.com/docs/reference/api/cms/blogs/blog-authors#post-%2Fcms%2Fv3%2Fblogs%2Fauthors). You can also [create blog authors directly in your HubSpot account](https://knowledge.hubspot.com/blog/create-and-manage-your-blog-authors#create-a-new-blog-author). ## Edit blog authors To update a blog author, make a `PATCH` request to `/cms/v3/blogs/authors/{objectId}`, where `objectId` is the ID of the associated author. Include a JSON payload representing the blog author model in your request. Review the required parameters and the structure of the blog author model in the [reference documentation](https://developers.hubspot.com/docs/reference/api/cms/blogs/blog-authors#patch-%2Fcms%2Fv3%2Fblogs%2Fauthors%2F%7Bobjectid%7D). You can also [edit a blog author's profile directly in your HubSpot account](https://knowledge.hubspot.com/blog/create-and-manage-your-blog-authors#edit-a-blog-author-s-profile). ## Multi-language management To help you maintain blog authors across multiple languages, HubSpot's CMS allows you to group together blog authors of language variants of the same content. A blog author with a language set may only be used on blog posts of the same language. Blog authors that do not have a language set are considered global and may be used on all blog posts. To learn more about working with multi-language blog authors, check out [this Knowledge Base article](https://knowledge.hubspot.com/blog/create-a-multi-language-blog#create-blog-authors-in-multiple-languages). ### Create a new language variant To create a new language variant for an existing blog author, make a `POST` request to `/multi-language/create-language-variant` and include a JSON payload containing the ID of the blog author to clone and the language identifier of the new variant. ### Attach a blog author to an existing multi-language group To add a blog author to an existing multi-language group, make a `POST` request to `/multi-language/attach-to-lang-group` and include a JSON payload containing the ID of the target blog author, the language identifier of the blog author being added, and the `primaryId` of the blog author designated as the primary author in the target multi-language group. ### Detach a blog author from a multi-language group To remove a blog author from a multi-language group, make a `POST` request to `/multi-language/detach-from-lang-group` endpoint, and include a JSON payload that contains the ID of the target blog author. # CMS API | Blog Posts @ The blog post endpoints are used to create and manage hubspot blog posts $ guides & api/cms/blogs --- # Blog Posts You can use the blog post API to publish and manage blog posts. Learn more about how to create and maintain your blog on the [HubSpot Knowledge Base.](https://knowledge.hubspot.com/web-content/topics#blog) ## Changes in V3 - The following properties are deprecated and will not be included in the response of any of the V3 endpoints: - `campaign_name` - `is_draft` - `keywords` - The `topicIds` property has been renamed to `tagIds`. ## Retrieve blog posts You can retrieve blog posts either individually by ID or by retrieving all blog posts: - To retrieve an individual blog post, make a `GET` request to `/cms/v3/blogs/posts/Welcome to my blog post! Neat, huh?
" } ``` | Parameter | Type | Description | | --- | --- | --- | | `name` | String | Description | | `contentGroupId` | String | The ID of the parent blog to publish the post to. You can retrieve the ID using the [blog details API](/reference/api/cms/blogs/blog-details). | | `slug` | String | The URL slug of the blog post. HubSpot will automatically generate the full URL using this value, along with the parent blog domain and slug. If no value is provided, the `name` value will be used as a temporary slug (hyphenated). You will need to set a specific slug before the post can be published. | | `blogAuthorId` | String | The ID of the blog author. You can retrieve this value using the [blog authors API](/reference/api/cms/blogs/blog-authors). | | `metaDescription` | String | The post's meta description. | | `useFeaturedImage` | Boolean | Whether to include a featured image for the blog post. By default, this field is set to `true`. To include a featured image, include a value for the `featuredImage` parameter. | | `postBody` | String | The HTML content of the blog post. | Editing blog post content directly in HubSpot using the content editor is the simplest way to modify content. While you can use the the API to create and update blog post, it's not recommended over using the editor, especially for blogs that rely on more complex modules. Learn more about the structure of the blog post model in the [blog posts endpoint reference](/reference/api/cms/blogs/blog-posts). ### Update a blog post You can update the draft version of a blog post by making a `PATCH` request to `/cms/v3/blogs/posts/Add a short description about the work that you do at your company. Try to narrow in on your specialization so that you can capture the attention of your clients. Talk about the value that you can deliver through a paid consultation.
", "path": "@hubspot/rich_text", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } } ], "type": "cell", "w": 6, "x": 6 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-8", "params": { "button_link": { "no_follow": false, "open_in_new_tab": false, "rel": "", "sponsored": false, "url": { "href": "#book" }, "user_generated_content": false }, "button_text": "Book a consultation", "child_css": {}, "css": {}, "css_class": "dnd-module", "path": "../modules/button", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "alignment": { "alignment": { "css": "", "horizontal_align": "CENTER" } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } } ], "styles": {}, "type": "cell", "w": 12, "x": 0 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-column-9", "params": { "css_class": "dnd-column" }, "rowMetaData": [ { "cssClass": "dnd-row", "styles": {} }, { "cssClass": "dnd-row" }, { "cssClass": "dnd-row" } ], "rows": [ { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-10", "params": { "child_css": {}, "css": {}, "css_class": "dnd-module", "extra_classes": "widget-type-rich_text", ", "path": "@hubspot/rich_text", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-11", "params": { "child_css": {}, "content": { "content": "Summarize the service you provide. Add a message about the value that you can provide to your customers.
" }, "css": {}, "css_class": "dnd-module", "icon": { "icon": { "icon_set": "fontawesome-5.0.10", "name": "balance-scale", "type": "SOLID", "unicode": "f24e" } }, "path": "../modules/service-card", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "card": { "spacing": { "spacing": { "css": "margin-bottom: 22px;\n", "margin": { "bottom": { "units": "px", "value": 22 } } } } }, "icon": { "background": { "color": { "color": "#494a52", "css": "#494a52", "hex": "#494a52", "opacity": 100, "rgb": "rgb(73, 74, 82)", "rgba": "rgba(73, 74, 82, 1)" } } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 4, "x": 0 }, "4": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-12", "params": { "child_css": {}, "content": { "content": "Summarize the service you provide. Add a message about the value that you can provide to your customers.
" }, "css": {}, "css_class": "dnd-module", "icon": { "icon": { "icon_set": "fontawesome-5.0.10", "name": "industry", "type": "SOLID", "unicode": "f275" } }, "path": "../modules/service-card", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "card": { "spacing": { "spacing": { "css": "margin-bottom: 22px;\n", "margin": { "bottom": { "units": "px", "value": 22 } } } } }, "icon": { "background": { "color": { "color": "#494a52", "css": "#494a52", "hex": "#494a52", "opacity": 100, "rgb": "rgb(73, 74, 82)", "rgba": "rgba(73, 74, 82, 1)" } } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 4, "x": 4 }, "8": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-13", "params": { "child_css": {}, "content": { "content": "Summarize the service you provide. Add a message about the value that you can provide to your customers.
" }, "css": {}, "css_class": "dnd-module", "icon": { "icon": { "icon_set": "fontawesome-5.0.10", "name": "server", "type": "SOLID", "unicode": "f233" } }, "path": "../modules/service-card", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "card": { "spacing": { "spacing": { "css": "margin-bottom: 22px;\n", "margin": { "bottom": { "units": "px", "value": 22 } } } } }, "icon": { "background": { "color": { "color": "#494a52", "css": "#494a52", "hex": "#494a52", "opacity": 100, "rgb": "rgb(73, 74, 82)", "rgba": "rgba(73, 74, 82, 1)" } } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 4, "x": 8 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-14", "params": { "button_link": { "no_follow": false, "open_in_new_tab": false, "rel": "", "sponsored": false, "url": { "href": "#book" }, "user_generated_content": false }, "button_text": "Book a consultation", "child_css": {}, "css": {}, "css_class": "dnd-module", "path": "../modules/button", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "alignment": { "alignment": { "css": "", "horizontal_align": "CENTER" } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } } ], "type": "cell", "w": 12, "x": 0 } } ], "type": "cell", "w": 12, "x": 0 } }, "name": "My test page", "pageRedirected": false, "publicAccessRules": [], "publicAccessRulesEnabled": false, "publishDate": "2024-03-28T18:48:55Z", "publishImmediately": true, "published": true, "slug": "my-test-page", "state": "PUBLISHED_OR_SCHEDULED", "subcategory": "site_page", "templatePath": "@hubspot/growth/templates/paid-consultation.html", "translations": {}, "updatedAt": "2024-03-28T18:49:44.134Z", "updatedById": "2931299", "url": "https://www.website.com/my-test-page", "useFeaturedImage": false, "widgetContainers": {}, "widgets": {} } ] } ``` ## Filtering When retrieving pages, you can add query parameters to the request URL to filter the results. Each filter will follow the same general syntax: `propertyName__operator=value`. You can include as many filters as you'd like, and all specified filters will be applied to narrow down the results.For example, you can filter the results to only include pages where the name property contains the word `marketing` using this parameter: `name__icontains=marketing`.The table below lists the page properties that can be used as filters, along with which operators each property can use. | Property | Available operators | | --- | --- | | `id` | `eq`, `in`, `not_in` | | `slug` | `eq`, `in`, `nin`, `icontains` | | `campaign` | `eq`, `in` | | `state` | `eq`, `ne`, `in`, `nin`, `contains`See [available states](#state-values) for filtering options. | | `publishDate` | `eq`, `gt`, `gte`, `lt`, `lte` | | `createdAt` | `eq`, `gt`, `gte`, `lt`, `lte` | | `updatedAt` | `eq`, `gt`, `gte`, `lt`, `lte` | | `templatePath` | `eq`, `contains`, `startswith` | | `name` | `eq`, `in`, `icontains` | | `mabExperimentId` | `eq`, `in` | | `abTestId` | `eq`, `in` | | `archivedAt` | `eq`, `gt`, `gte`, `lt`, `lte` | | `createdById` | `eq` | | `updatedById` | `eq` | | `domain` | `eq`, `not_like`, `contains`This will display as blank for content published on a domain that is primary for that content type. | | `subcategory` | `eq`, `ne`, `in`, `nin` | | `folderId` | `eq`, `in`, `null`, `not_null` | | `language` | `in`, `not_null` | | `translatedFromId` | `null`, `not_null` | | `dynamicPageHubDbTableId` | `eq`, `not_null` | Below are the definitions for each operator, along with any available synonyms. | Operator | Description | | --- | --- | | `eq` | Filters for results that are equal to the specified value.Synonyms: `exact`, `is` | | `ne` | Filters for results that are not equal to the specified value.Synonyms: `neq`, `not` | | `contains` | Filters for results that contain the specified, case-sensitive value. Not accepted for the `name` property.Synonym: `like`. | | `icontains` | Filters for results by the specified value, not case sensitive. Synonym: `ilike`. | | `not_like` | Filters for results that don't contain a specified value.Synonym: `nlike` | | `lt` | Filters for results that are less than a specified number value, such as a unix timestamp in milliseconds. | | `lte` | Filters for results that are less than or equal to a specified value. | | `gt` | Filters for results that are greater than a specified value. | | `gte` | Filters for results that are greater than or equal to a specified value. | | `is_null` | Filters for results that do not have a value for the specified property. | | `not_null` | Filters for results that have any value for the specified property. | | `startswith` | Filters for results that start with a specified value. | | `in` | In | | `nin` | Not in | ### State values To retrieve pages with a given publish state, include the `state__in=` query parameter with the following values: **Draft:** `DRAFT`, `DRAFT_AB`, `DRAFT_AB_VARIANT`, `LOSER_AB_VARIANT` **Scheduled:** `PUBLISHED_OR_SCHEDULED`, `SCHEDULED_AB` **Published:** `PUBLISHED_OR_SCHEDULED`, `PUBLISHED_AB`, `PUBLISHED_AB_VARIANT` Because both scheduled and published pages will reflect a `PUBLISHED_OR_SCHEDULED` state, it's recommended to also include a `publishDate` parameter to better understand the page's current state. For example, to identify the pages that are currently scheduled but not yet published, your request URL should include a `publishDate` parameter that uses the `gt` (greater than) operator with the current datetime specified. This will filter for pages with a publish time in the future: `state__in=PUBLISHED_OR_SCHEDULED&publishDate__gt={currentTime}` To identify the pages that are already published, your request URL would similarly include a publishDate parameter, but you would use the `lt` (less than) operator with the current datetime specified. `state__in=PUBLISHED_OR_SCHEDULED&publishDate__lt={currentTime}` `currentState` is a generated field which cannot be used as a filter. This field will reflect the page's current publish state. ### A/B filters When filtering for A/B test pages, you can use the following filters: | Description | Query Params | | --- | --- | | Active A page or winning variant of a completed A/B test | `abStatus__eq=MASTER` | | Active B page | `abStatus__eq=VARIANT` | | Losing variant of a completed A/B test | `abStatus__eq=LOSER_VARIANT` | - An A/B test is running only when there are published, active A and B pages. - An A/B test is complete when a winning and losing variant have been selected, i.e. there isn’t an active B page. ### Multi-language filters When filtering for multi-language pages, you can use the following filters: | Description | Query Params | | --- | --- | | Primary page in a multi-language group | `translatedFromId__is_null` | | Variation page in a multi-language group | `translatedFromId__not_null` | | Page with specific Language\* (German) | `language__in=de`Does not support language locale values (e.g., `en-us`) | ## Sorting To sort results, you can add a `sort` query parameter to your request URL, followed by the property name. You can reverse the sort by adding a `-` to the property name. For example: `sort=-publishDate`.By combining query parameters for filtering, sorting and paging, you can retrieve the pages that match your search criteria. For example, the request below fetches landing pages that do not have a language assigned, ordered by most recently updated. The limit and offset parameters below return the second page of results. ```shell curl https://api.hubapi.com/cms/v3/pages/landing-pages?sort=-updatedAt&&language__not_null&limit=10&offset=10 \ --request POST \ --header "Content-Type: application/json" ``` ## Create pages To create a website page, make a `POST` request to `/cms/v3/pages/site-pages`. In the request body, you'll include a JSON payload that sets the page's details along with the page content contained in the `layoutSections` object. The required fields when creating a page are `name` and `templatePath`.For `templatePath`, the path should not include a slash (`/`) at the start. When using the _Copy path_ function in the design manager, this slash will be included automatically but should be removed after pasting it into your request body.To set the URL of a page, set the `domain` and `slug` fields. Note that the `url` field is generated and cannot be updated. Learn more about [creating and customizing pages within HubSpot](https://knowledge.hubspot.com/website-and-landing-pages/create-and-customize-pages). You can create the page as a draft so that it's not yet published by setting the `state` to `DRAFT`. See [available states](#state-values) for more information. ```json // Example request body { "domain": "", "htmlTitle": "My draft", "name": "My test page", "slug": "my-test-page", "state": "DRAFT", "templatePath": "@hubspot/growth/templates/paid-consultation.html", "url": "https://www.bird.estate/my-draft", "useFeaturedImage": false, "layoutSections": { "dnd_area": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "label": "Main section", "name": "dnd_area", "params": {}, "rowMetaData": [ { "cssClass": "dnd-section", "styles": { "backgroundColor": { "a": 1, "b": 250, "g": 248, "r": 245 }, "forceFullWidthSection": false } }, { "cssClass": "dnd-section", "styles": { "backgroundColor": { "a": 1, "b": 255, "g": 255, "r": 255 }, "forceFullWidthSection": false } } ], "rows": [ { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-column-2", "params": { "css_class": "dnd-column" }, "rowMetaData": [ { "cssClass": "dnd-row" }, { "cssClass": "dnd-row" }, { "cssClass": "dnd-row" } ], "rows": [ { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-3", "params": { "child_css": {}, "css": {}, "css_class": "dnd-module", "extra_classes": "widget-type-rich_text", ", "path": "@hubspot/rich_text", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-column-4", "params": { "css_class": "dnd-column" }, "rowMetaData": [ { "cssClass": "dnd-row", "styles": {} } ], "rows": [ { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-5", "params": { "child_css": {}, "css": {}, "css_class": "dnd-module", "extra_classes": "widget-type-linked_image", "horizontal_alignment": "CENTER", "img": { "alt": "Growth theme placeholder image", "loading": "lazy", "max_height": 500, "max_width": 500, "size_type": "auto_custom_max", "src": "//7528309.fs1.hubspotusercontent-na1.net/hubfs/7528309/raw_assets/public/mV0_d-cms-growth-theme_hubspot/growth/images/service-one.jpg" }, "path": "@hubspot/linked_image", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "style": "margin-bottom: 22px;", "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "styles": { "flexboxPositioning": "TOP_CENTER" }, "type": "custom_widget", "w": 12, "x": 0 } } ], "type": "cell", "w": 6, "x": 0 }, "6": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-column-6", "params": { "css_class": "dnd-column" }, "rowMetaData": [ { "cssClass": "dnd-row" } ], "rows": [ { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-7", "params": { "child_css": {}, "css": {}, "css_class": "dnd-module", "extra_classes": "widget-type-rich_text", "html": "Add a short description about the work that you do at your company. Try to narrow in on your specialization so that you can capture the attention of your clients. Talk about the value that you can deliver through a paid consultation.
", "path": "@hubspot/rich_text", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } } ], "type": "cell", "w": 6, "x": 6 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-8", "params": { "button_link": { "no_follow": false, "open_in_new_tab": false, "rel": "", "sponsored": false, "url": { "href": "#book" }, "user_generated_content": false }, "button_text": "Book a consultation", "child_css": {}, "css": {}, "css_class": "dnd-module", "path": "../modules/button", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "alignment": { "alignment": { "css": "", "horizontal_align": "CENTER" } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } } ], "styles": {}, "type": "cell", "w": 12, "x": 0 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-column-9", "params": { "css_class": "dnd-column" }, "rowMetaData": [ { "cssClass": "dnd-row", "styles": {} }, { "cssClass": "dnd-row" }, { "cssClass": "dnd-row" } ], "rows": [ { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-10", "params": { "child_css": {}, "css": {}, "css_class": "dnd-module", "extra_classes": "widget-type-rich_text", ", "path": "@hubspot/rich_text", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-11", "params": { "child_css": {}, "content": { "content": "Summarize the service you provide. Add a message about the value that you can provide to your customers.
" }, "css": {}, "css_class": "dnd-module", "icon": { "icon": { "icon_set": "fontawesome-5.0.10", "name": "balance-scale", "type": "SOLID", "unicode": "f24e" } }, "path": "../modules/service-card", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "card": { "spacing": { "spacing": { "css": "margin-bottom: 22px;\n", "margin": { "bottom": { "units": "px", "value": 22 } } } } }, "icon": { "background": { "color": { "color": "#494a52", "css": "#494a52", "hex": "#494a52", "opacity": 100, "rgb": "rgb(73, 74, 82)", "rgba": "rgba(73, 74, 82, 1)" } } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 4, "x": 0 }, "4": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-12", "params": { "child_css": {}, "content": { "content": "Summarize the service you provide. Add a message about the value that you can provide to your customers.
" }, "css": {}, "css_class": "dnd-module", "icon": { "icon": { "icon_set": "fontawesome-5.0.10", "name": "industry", "type": "SOLID", "unicode": "f275" } }, "path": "../modules/service-card", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "card": { "spacing": { "spacing": { "css": "margin-bottom: 22px;\n", "margin": { "bottom": { "units": "px", "value": 22 } } } } }, "icon": { "background": { "color": { "color": "#494a52", "css": "#494a52", "hex": "#494a52", "opacity": 100, "rgb": "rgb(73, 74, 82)", "rgba": "rgba(73, 74, 82, 1)" } } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 4, "x": 4 }, "8": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-13", "params": { "child_css": {}, "content": { "content": "Summarize the service you provide. Add a message about the value that you can provide to your customers.
" }, "css": {}, "css_class": "dnd-module", "icon": { "icon": { "icon_set": "fontawesome-5.0.10", "name": "server", "type": "SOLID", "unicode": "f233" } }, "path": "../modules/service-card", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "card": { "spacing": { "spacing": { "css": "margin-bottom: 22px;\n", "margin": { "bottom": { "units": "px", "value": 22 } } } } }, "icon": { "background": { "color": { "color": "#494a52", "css": "#494a52", "hex": "#494a52", "opacity": 100, "rgb": "rgb(73, 74, 82)", "rgba": "rgba(73, 74, 82, 1)" } } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 4, "x": 8 } }, { "0": { "cells": [], "cssClass": "", "cssId": "", "cssStyle": "", "name": "dnd_area-module-14", "params": { "button_link": { "no_follow": false, "open_in_new_tab": false, "rel": "", "sponsored": false, "url": { "href": "#book" }, "user_generated_content": false }, "button_text": "Book a consultation", "child_css": {}, "css": {}, "css_class": "dnd-module", "path": "../modules/button", "schema_version": 2, "smart_objects": [], "smart_type": "NOT_SMART", "styles": { "alignment": { "alignment": { "css": "", "horizontal_align": "CENTER" } } }, "wrap_field_tag": "div" }, "rowMetaData": [], "rows": [], "type": "custom_widget", "w": 12, "x": 0 } } ], "type": "cell", "w": 12, "x": 0 } } ], "type": "cell", "w": 12, "x": 0 } } } ``` ## Editing pages Pages in HubSpot have both draft and live versions. The draft version may be updated without affecting the live page content. Drafts can be reviewed and then published by a user working in HubSpot. They may also be scheduled for publication at a future time via the `/schedule` endpoint. Draft changes can be discarded via the `/reset` endpoint, allowing users to go back to the current live version of the page without disruption. ### Edit Draft The draft version of a page can be updated via a `PATCH` request to the `{objectid}/draft` endpoint. This endpoint accepts a JSON payload representing the page model.Modifying the content of a page via these APIs is _not_ recommended -- the content editor in HubSpot is the simplest way to modify website content.You can modify the `widgets`, `widgetContainers`, and `layoutSections` properties via this endpoint. They store page-level module data, contained directly in the template (`widgets`), within flex columns (`widgetContainers`) and in drag-and-drop areas (`layoutSections`).The properties provided in the supplied payload will override the existing draft properties without any complex merging logic. Consequently, when updating nested properties such as those within the `widgets`, `widgetContainers`, or `layoutSections` of the page, you must include the full definition of the object. Partial updates are not supported. ### Reset Draft The draft version of a page can be reset to the current live version via a `POST` request to the `{objectId}/draft/reset` endpoint. This endpoint accepts no payload and simply reverts the draft version of the target page to match the current live version. ## Publishing pages Unpublished changes to a published page can be pushed live via a `POST` request to the `{objectId}/draft/push-live` endpoint. This endpoint accepts no payload and will only update an already published page, not publish a drafted page. ### Publish Draft (Scheduled) The draft version of a page can be scheduled for publication at a future time via a `POST` request to the `schedule` endpoint. This endpoint accepts a JSON payload containing the `id` of the target page and a `publishDate`. Learn more about [scheduling page publication.](https://knowledge.hubspot.com/website-pages/use-advanced-publishing-features) ## A/B testing A/B tests can be used to tune and optimize content by splitting traffic to a page across two variants of differing formats. Conversion rate of each page is monitored over time so that a winner can be chosen based on the relative success of each variant. Learn more about [running A/B tests in HubSpot](https://knowledge.hubspot.com/website-pages/run-an-a-b-test-on-your-page). The following properties will be populated on pages with active or completed A/B tests: - `abTestId`: Unique identifier for the page’s associated A/B test - `abStatus`: Indicates whether the page is an A/B primary, variant, or loser variant #### Create Test An A/B test variant can be created via a `POST` request to the `ab-test/create-variation` endpoint. This endpoint accepts a JSON payload containing the `contentId` of the page to test and a `variationName` for the variant to be created.Upon creation, the new test variant can be [updated](#editing-pages) and [published](#publishing-pages) in the same manner as a standard page. #### End Test Once enough traffic has been monitored across each variant and a clear winner has been determined, an A/B test can be terminated via a `POST` request to the `ab-test/end` endpoint. This endpoint accepts a JSON payload containing the `abTestId` of the target A/B test and the `winnerId` of the content deemed the winner. ## Multi-language content In HubSpot, you can group together language variants of the same content. Learn more about [working with multi-language pages in HubSpot](https://knowledge.hubspot.com/website-and-landing-pages/create-pages-in-multiple-languages#create-a-multi-language-variation-of-a-page). The following properties will be populated on pages within a multi-language group: - `translatedFromId`: unique identifier for the primary language page of the multi-language group. This property will be null on the primary page itself. - `language`: the ISO 639 code representing the language of the page. - `translations`: a map of ISO 639 codes to variant page objects within the multi-language group. #### Create a New Language Variant A new language variant of an existing page can be created via a `POST` request to the `multi-language/create-language-variant` endpoint. This endpoint accepts a JSON payload containing the `id` of the page to clone and the `language` identifier of the new variant. #### Attach a Page to an Existing Multi-Language Group A page can be added to an existing multi-language group via a `POST` request to the `multi-language/attach-to-lang-group` endpoint. This endpoint accepts a JSON payload containing the `id` of the target page, the `language` identifier of the page being added, and the `primaryId` of the page designated as the primary page in the target multi-language group. #### Detach a Page from a Multi-Language Group A page can be removed from a multi-languages group via a `POST` request to the `multi-language/detach-from-lang-group` endpoint. This endpoint accepts a JSON payload containing the `id` of the target page. # CMS API | Site search @ This endpoint is used to search for content across multiple domains $ guides & api/cms --- Site search allows you to return content related to a search term for HubSpot-hosted sites. Additionally, you can return all indexed data for a given document ID (page ID, post ID, HubDB row ID, etc.). If Google is used to search the entire web, site search indexes an entire website and produces search results in an easy-to-read list. From ecommerce to news outlets, this functionality is commonplace and useful in many different types of applications. **Example use case:** Set up a results page to use a search field on your HubSpot-hosted site. See [knowledge article](https://knowledge.hubspot.com/cos-general/how-do-i-set-up-a-results-page-for-my-search-field-in-hubspot) for more information. **Note**: The search endpoint is used to search content across multiple domains. # CMS | Source Code API @ Create, fetch, update, and delete, files in the HubSpot developer file system. Additionally you can validate files for different types of errors & warnings $ guides & api/cms --- # CMS Source Code ## Basic Features The CMS Source Code API allows you to interact with the files stored in your HubSpot [Developer File System](/guides/cms/overview#developer-file-system). These files include all of the templates, modules, CSS, JS, and other CMS assets seen in the Design Manager. Through this API, you can: - Upload new files to their HubSpot account, or upload changes to existing files. - Download or delete CMS assets from their account. - Fetch metadata for each file or folder in the Design Manager. - Validate file contents for use in HubSpot CMS, including HubL syntax. - Upload zip files as file packages and extract them inside the account. With this API you can edit all your CMS assets locally as well as build tooling to help you move even faster. ## Environment and path The Source Code API endpoints use the `environment` and `path` parameters to identify files in the CMS Developer File System. These parameters are generally specified in the endpoint path itself, as in `/cms/v3/source-code/{environment}/content/{path}`. The `environment` parameter refers to whether you are interacting with the unpublished or live version of each file. For unpublished changes, use `draft`. For live changes, use `published`. Note that uploading to `published` is equivalent to pressing the “Publish” button in the Design Manager. As such, whatever is currently in `draft` will be cleared. The `path` parameter refers to the location of the file in the CMS Developer File System. Top level assets are not preceded by a `/` character as you would see in a UNIX based operating system. When uploading a new file, this should be the desired location where the file should be created. When retrieving or uploading changes to an existing file, this should match the path of the existing file. We use the local file formats for all asset types, which means that certain types of assets are broken up into multiple files. For instance, a module is actually represented as a directory ending in the `.module` suffix, so to retrieve the HTML for a module, one would need to use the path `foo.module/module.html`. See the [local development documentation](/guides/cms/tools/local-development-cli) for further information. ## Downloading a file To download a file from your HubSpot account, make a `GET` request to `/cms/v3/source-code/{environment}/content/{path}` and set the header to `Accept: application/octet-stream`. File data will be downloaded in binary format. You cannot download the entire contents of a folder. Instead, you must fetch the folder metadata and retrieve each of its children individually. ## Fetching file and folder metadata To fetch file and folder metadata, such as path, filename, and created/updated timestamps, make a `GET` request to `/cms/v3/source-code/{environment}/metadata/{path}` and set the header to `Accept: application/json`. File and folder metadata will be returned in a JSON object: - Folder metadata will be indicated by the `folder: true` property. - The `children` array will show the names of files and subfolders within the folder. These filenames can be used to traverse the folder tree: simply fetch one folder metadata and recursively fetch the children of the folder and all subfolders. ## Uploading a file To upload a local file to your HubSpot account, make a `PUT` request to `/cms/v3/source-code/{environment}/content/{path}`. You must upload the file using the `multipart/form-data` content type, and the binary file data must be included as a field named `file`. For example: - **Uploading a new file:** PUT `/cms/v3/source-code/published/content/my-new-file.html` `Content-Type: multipart/form-data` `Form Data: { file: [_binary file data_] }` - **Updating an existing file draft:** PUT `/cms/v3/source-code/draft/content/path/to/existing-file.html` `Content-Type: multipart/form-data` `Form Data: { file: [_binary file data_] }` HubSpot currently supports the following file types: - `css` - `js` - `json` - `html` - `txt` - `md` - `jpg` - `jpeg` - `png` - `gif` - `map` - `svg` - `ttf` - `woff` - `woff2` - `zip` ## Validating file contents To validate the contents of a local file, make a `POST` request to `/cms/v3/source-code/{environment}/validate/{path}`. You must upload the file using the `multipart/form-data` content type, and the binary file data must be included as a field named `file`. This can be used to validate HubL in a template/module or JSON for a theme or module. If there are validation errors, you will receive a `400` response with the list of relevant errors. These are the same warnings and errors you would see within the design manager. Note that invalid files will be rejected if you try and publish them directly. It is recommended to validate files first before publishing. **For example:** POST `/cms/v3/source-code/published/validate/my-file.html` `Content-Type: multipart/form-data` `Form Data: { file: [_binary file data_] }` ## Deleting a file To delete a file, make a `DELETE` request to `/cms/v3/source-code/{environment}/content/{path}`. Deleting from the `published` environment will remove the file entirely, while deleting from the `draft` environment will simply clear out any unpublished changes. Note that deleting published files will immediately impact live content if used anywhere, so make sure to remove all existing references to the file before deleting. ## Extracting a file package To extract a zip file, make a `POST` request to `/cms/v3/source-code/extract/{path}`. The `path` must be a zip file already uploaded to the account. The extraction process is asynchronous and can take up to a minute depending on how many and how large the compressed files are. The contents of the zip are extracted in place to the same folder that contains the zip file, and the original zip file is not deleted automatically upon successful extraction. # CMS API | URL redirects @ This endpoint can be used to manage URL redirects for a portal $ guides & api/cms --- URL redirects allow you to redirect traffic from a HubSpot-hosted page or blog post to any URL. You can also update [URL redirects in bulk](https://knowledge.hubspot.com/articles/kcs_article/cos-general/how-to-bulk-upload-url-mappings-to-hubspot) and use a [flexible pattern redirect](https://knowledge.hubspot.com/cos-general/how-do-i-set-up-a-flexible-pattern-url-mapping) to dynamically update the structure of URLs. # Custom channels @ Learn how to define custom channels in the conversations inbox and help desk. $ guides & api/conversations --- # Custom channels You can create custom channels to build a bridge between an external message service and HubSpot's [inbox](https://knowledge.hubspot.com/inbox/set-up-the-conversations-inbox) or [help desk](https://knowledge.hubspot.com/help-desk/overview-of-the-help-desk-workspace) features. You can then publish your custom channel app in the HubSpot App Marketplace for other HubSpot admins to install and use in their own accounts. You'll need to create a public app if you want to define and register custom channels. The custom channel endpoints are **not** supported when building a private app. ## Create a public app To get started, you'll need to create a public app that you'll use to register your custom channel with HubSpot, then handle incoming and outgoing messages to an inbox. You can follow the instructions in [this article](/guides/apps/public-apps/overview) to create your public app. When configuring the scopes for your app on the _Auth_ tab, ensure that your app requests the following scopes: - `conversations.custom_channels.read`: this scope allows you to access to read messages and threads that your custom channel has already published to HubSpot. - `conversations.custom_channels.write`: this scope allows you to publish messages to HubSpot. - `conversations.read`: this scope allows you to retrieve a list of conversation inboxes in an account using the [Conversations BETA API](/guides/api/conversations/inbox-and-messages#inboxes), so that you can connect channel accounts to specific inboxes. Once you've created your app, take note of the following app details that you'll use to identify your app when making requests to the Custom Channels API endpoints. - App ID - Client ID - Client secret ## Register your custom channel in HubSpot After creating your app, you can create your custom channel in HubSpot, using your HubSpot Developer API Key, and your App ID of the app you just created. To register your channel, make a `POST` request to `https://api.hubapi.com/conversations/v3/custom-channels?hapikey={YOUR_DEVELOPER_API_KEY}&appId={appId}`. In the body of your request, you'll specify the configuration and capabilities for your channel: - Specify the user-facing channel name as the value for the `name` field. - Provide a channel schema that includes an object that details the channel capabilities as the value for the `capabilities` field. - Certain fields are optional and can be updated later using a `PATCH` request: - You can also specify a `webhookUrl` for handling webhook events (e.g., handling [updates to channel accounts](#handling-updates-to-channel-accounts)). - You can include a `channelDescription` and `channelLogoUrl` that will appear in the setup flow for your channel. - Specify a redirect URL that users will be sent to after completing your setup flow with the `channelAccountConnectionRedirectUrl` field. For example, the following request body provides an example channel schema with a set of basic channel capabilities: ```json // Example request body for registering a custom channel { "name": "My new custom channel", "webhookUrl": "https://example.com/handle-new-outgoing-message-notification", "capabilities": { "deliveryIdentifierTypes": [], "richText": ["HYPERLINK", "TEXT_ALIGNMENT", "BLOCKQUOTE"], "allowInlineImages": false, "allowOutgoingMessages": false, "outgoingAttachmentTypes": ["FILE"], "allowedFileAttachmentMimeTypes": ["image/png"], "maxFileAttachmentCount": 1, "maxFileAttachmentSizeBytes": 1500000, "maxTotalFileAttachmentSizeBytes": 1500000, "threadingModel": "INTEGRATION_THREAD_ID" }, "channelAccountConnectionRedirectUrl": "https://example.com/path-back-to-your-connection-flow", "channelDescription": "Respond to prioritized messages via our custom channel", "channelLogoUrl": "https://example.com/logo.png" } ``` ### Channel schema The table below outlines each of the available parameters for the channel schema in the request body. | Parameter | Type | Description | | --- | --- | --- | | `name` | String | The name of your channel, which will appear to users who install your app. | | `webhookUrl` | String | A valid URL where HubSpot will send webhook notifications of outgoing messages that should be sent using your channel. This field is not required when initially registering the channel. | | `capabilities` | Object | An object that specifies that the messaging content and recipient capabilities of your channel. Consult the table below for all supported fields for this object. | | `channelAccountConnectionRedirectUrl` | String | If you're [creating a connection setup flow for your custom channel](#creating-a-connection-setup-flow-for-your-custom-channel), this is the URL that HubSpot will point to when users click the option to install your app in the inbox or help desk connection setup in HubSpot. This field is not required when initially registering the channel. | | `channelDescription` | String | A string that will provide context under the channel when connecting it to HubSpot. This field is not required when initially registering the channel. See the [section below](#creating-a-connection-setup-flow-for-your-custom-channel) on defining a setup flow for your custom channel. | | `channelLogoUrl` | String | A URL that points to a logo that appear for your channel when connecting it to HubSpot. This field is not required when initially registering the channel. See the [section below](#creating-a-connection-setup-flow-for-your-custom-channel) on defining a setup flow for your custom channel. | ### Channel capabilities The table below outlines all available fields you can specify for the `capabilities` field of your channel. | Parameter | Type | Description | Default | | --- | --- | --- | --- | | `deliveryIdentifierTypes` | Array | A required array that specifies the identifier types your channel supports for its senders and recipients. Consult the delivery identifier types table below for more info. | `[]` | | `richText` | Array | An optional array of supported rich text elements presented as options in HubSpot's message composer. Available values are `"BLOCKQUOTE"`, `"BOLD"`, `"FONT_SIZE"`, `"FONT_STYLE"`, `"HYPERLINK"`, `"ITALIC"`, `"LISTS"`, `"TEXT_ALIGNMENT"`, `"TEXT_HIGHLIGHT_COLOR"`, `"TEXT_COLOR"`, and/or `"UNDERLINE"`. If left unspecified, no rich text elements will be supported. | `[]` | | `allowInlineImages` | Boolean | Whether your channel allows inline images to be included in the message body. If set to `true`, HubSpot's message composer will present an _Insert image_ option. | `False` | | `allowOutgoingMessages` | String | Whether your channel allows outgoing messages. You can set this field to true if you want your channel to be an "intake-only" message source. | `False` | | `outgoingAttachmentTypes` | Array | The types of attachments your channel supports (valid values are `"FILE"` and `"QUICK_REPLIES"`). | `[]` | | `allowedFileAttachmentMimeTypes` | Array | The file MIME types that your channel supports for file attachments, if any. This defaults to a fairly permissive list of common text, image, audio, video, and archive files. | `["image/png", "text/plain", ...]` | | `maxFileAttachmentCount` | Integer | The maximum number of file attachments permitted for a single message. | `0` | | `maxFileAttachmentSizeBytes` | Integer | The maximum individual file size permitted for a single attachment on a message, in bytes. | `0` | | `maxTotalFileAttachmentSizeBytes` | Integer | The maximum cumulative file size permitted for all attachments combined for a single message, in bytes. | `0` | | `threadingModel` | String | An enumeration denoting which threading model to use for messages. Values are: `INTEGRATION_THREAD_ID` and `DELIVERY_IDENTIFIER`. See the section below for more information. | `INTEGRATION_THREAD_ID` | ### Specifying a threading model By default, the threading model of your custom channel is set to `INTEGRATION_THREAD_ID`, where you're required to include an `integrationThreadId` in every `POST` [message request](#incoming-message-schema). This ID will always be returned in the `channelIntegrationThreadIds` property of the `OUTGOING_CHANNEL_MESSAGE_CREATED` [webhook event](#handling-outgoing-messages-sent-from-hubspot). You can optionally set your threading model to `DELIVERY_IDENTIFIER`, which is a good fit when there is only ever one open coversation between parties. If you set the `threadingModel` to this value within the `capabilities` [object](#channel-capabilities) of your channel, you should _not_ include an `integrationThreadId` in any of your `POST` [message requests](#incoming-message-schema), because HubSpot will generate and manage its own `threadIds` based on the following rules: - A set of `deliveryIdentifiers` (e.g., email address, phone numbers, or other identifiers in the sender and/or recipients array of a message) may have a maximum of one active thread between these delivery identifiers at once. - Archived threads between that same set of participants are ignored. - Outgoing messages can only be published on open threads, adn there can only be one thread between a specific set of participants at a time. - Incoming messages can only be published to the same `threadId` if either of the following conditions are met: - The thread is already open. - The thread was closed with the latest message activity occurring less than 24 hours ago, in which case the published incoming message will re-open the thread. - The `channelIntegrationThreadIds` property within the payload of the `OUTGOING_CHANNEL_MESSAGE_CREATED` [webhook event](#handling-outgoing-messages-sent-from-hubspot) will contain the value of the `threadId` that HubSpot created. ### Delivery identifiers The `deliveryIdentifierTypes` field specified within the `channelCapabilities` of your channel specifies an array of delivery identifiers. A delivery identifier is an object that includes a `type` and `value`, that describes sender or recipient delivery details: | Parameter | Type | Description | | --- | --- | --- | | `type` | String | The format for an identifier of the sender or recipient. Much like a postal mail address, this identifier provides a well-defined format for sending or receiving messages to/from the individual contact. The following types are available:Can you follow up?
" } ``` ### Send messages to threads Using this endpoint, an integration can send outgoing messages as a user in a HubSpot account. These messages are sent from the channel, just like if a user typed and sent a response in the inbox. To send a message to an existing thread, make a `POST` request to `conversations/v3/conversations/threads/{threadId}/messages`. When sending a message to a thread, you can include the following fields. You can include both the message details, as well as recipient information, in the request body. | Field | Description | | --- | --- | | `type` | The type of message you're sending. This value can either be `MESSAGE` or `COMMENT`. | | `text` | The content of the message. | | `richText` | The content of the message in HTML format. This is optional. | | `recipients` | An object representing the recipients of the message. This is the most important for email, where you can specify multiple recipients. This object includes the following fields:`actorID`: the ID associated with the message recipient.`name`: the name of the recipient.`recipientField`: for email messages, this is the type of recipient. Available values are `TO`, `CC`, or `BCC`.`deliveryIdentifiers`: for email messages, this indicates the email addresses used for the visitor and agent. | | `senderActorId` | This must be an agent actor ID that is associated to the HubSpot user in the account who is sending the message. | | `channelId` | The ID of a generic channel returned from the channels endpoint, like `1000` for live chat, `1001` for Facebook Messenger, `1002` for email, etc. | | `channelAccountId` | The ID of an account that is part of the `channelId` channel. On an existing thread, it is recommended to copy the `channelId` and `channelAccountId` of the most recent message on the thread. | | `subject` | The subject line of the email. This is ignored when sending a message to a non-email channel. | | `attachments` | Any attachments to attach to the message, which can be specified as an object that contains a URL to a file hosted in your HubSpot account, or a list of quick replies if you're sending a message via Facebook Messenger or LiveChat. Learn more about how to include attachments [in the section below.](#include-attachments-in-messages) | For example, your request body may look similar to the following: ```json // POST request to conversations/v3/conversations/threads/{threadId}/messages { "type": "MESSAGE", "text": "Hey there, following up", "richText": "Hey there, following up
", "recipients": [ { "actorId": "E-user@hubspot.com", "name": "Leslie Knope", "recipientField": "TO", "deliveryIdentifiers": [ { "type": "HS_EMAIL_ADDRESS", "value": "lknope@hubspot.com" } ] } ], "senderActorId": "A-3892666", "channelId": "1002", "channelAccountId": "42423411", "subject": "Follow up" } ``` If you make a successful request, the new message will be sent to the visitor. This can appear as a message in the chat widget, an email in the thread, a message in Facebook Messenger, etc. ## Include attachments in messages Attachments can be links to a file hosted in the HubSpot files tool, or a set of quick replies if you're sending a message using Facebook Messenger or LiveChat. To include an attachment from a file in your HubSpot account, provide the absolute URL as the `fileId` in the `attachments` field of the request body. For example, the corresponding part of the request body is shown in lines `10-12` below: ```json // POST request to conversations/v3/conversations/threads/{threadId}/messages { "type": "MESSAGE", "text": "Hey there, following up", "recipients": { "actorID": "E-user@hubspot.com", "name": "Leslie Knope", "recipientField": "TO", "deliveryIdentifiers": [ { "type": "HS_EMAIL_ADDRESS", "value": "lknope@hubspot.com" } ] }, "senderActorId": "A-3892666", "channelId": "1002", "channelAccountId": "424232411", "subject": "Follow up", "attachments": { "fileId": "https://12345678.fs1.hubspotusercontent-na1.net/hubfs/12345678/doggo_video.mp4" } } ``` If you connected Facebook Messenger or LiveChat as a channel, you can also specify a set of quick replies within the `attachments` field, which prompt the recipient with certain options that appear as tappable buttons below a message. Once tapped, the corresponding value of that option will be recorded. Quick replies should be provided as a list of objects that each contain the following fields: - `label`: the visible text that appears to the recipient (e.g., _Red_) - `value`: the associated value of the button that you want to record (e.g., `RED`) - `valueType`: the type of the quick reply option, which can be either `TEXT` or `URL`. The example request body below demonstrates how to specify two quick reply options, _Yes_ and _No_, on lines `10-23`: ```json // POST request to conversations/v3/conversations/threads/{threadId}/messages { "type": "MESSAGE", "text": "Did that answer your question?", "recipients": { "actorID": "E-user@hubspot.com", "name": "Leslie Knope", "recipientField": "TO", "deliveryIdentifiers": [{"type": "HS_EMAIL_ADDRESS", "value": "lknope@hubspot.com"}]}, "senderActorId": "A-3892666", "channelId": "1002", "channelAccountId": "424232411", "subject": "Follow up", "attachments": [ "type": "QUICK_REPLIES", "quickReplies": [ { "label": "Yes", "value": "Yes", "valueType": "URL" }, { "label": "No", "value": "No", "valueType": "TEXT" } ] ] } ``` ## Webhooks Webhooks for conversations are also supported and can be used in tandem with the conversations API. You can use webhooks to subscribe to events about conversations, including thread creation, thread status and assignment changes, and new messages on threads. Learn more about using [webhooks](/guides/api/app-management/webhooks). You must have the `conversations.read` scope to get access to following webhooks. The available conversation webhook events are: | Event | Description | | --- | --- | | `conversation.creation` | A new Conversations thread has been created. | | `conversation.deletion` | A Conversations thread has been archived. | | `conversation.privacyDeletion` | A Conversations thread has been permanently deleted. | | `conversation.propertyChange` | A property of a Conversations thread has been updated. | | `conversation.newMessage` | A new message has been posted on a Conversations thread. | The available properties for each event type are: | Event | Properties | | --- | --- | | `All events` | `objectId`: the ID of the Conversations thread that the webhook corresponds to. | | `conversation.propertyChange` | `assignedTo`: a thread's assignment has changed. The value is the user ID of the new assignee, unless the owner was removed.`status`: a thread's status has changed, either to `OPEN` or `CLOSED`.`isArchived`: when a thread is restored a `conversation.propertyChange` webhook will be sent and the value will be `false`. | | `conversation.newMessage` | `messageId`: the ID of the new message.`messageType`: the type of the new message. One of `MESSAGE`, `COMMENT`, `WELCOME_MESSAGE`. | # @ Learn how to use the HubSpot mobile chat SDK in your Android app. $ guides & api/conversations/mobile-chat-sdk --- # Integrate the HubSpot mobile chat SDK into your Android app You can use the HubSpot mobile chat SDK to integrate your Android mobile application with HubSpot's live chat functionality. The mobile chat SDK allows you to: - Integrate HubSpot chat into your mobile app to deliver real-time, in-app customer support. - Leverage the [bot](https://knowledge.hubspot.com/chatflows/create-a-bot) and [knowledge base](https://knowledge.hubspot.com/knowledge-base/create-and-customize-knowledge-base-articles) tools to help deflect customer inquires when your support agents are unavailable. - Alert users of new messages via push notifications. - Customize the chat experience to align with your business's brand and UI. ## Set up and run the demo app To set up the mobile chat SDK dependencies to your project: - Add your `google-services.json` in the `app/` folder, and ensure that the `package_name` field in the file is set to `com.example.demo`. - Create your `hubspot-info.json` file in the `app/` folder. The full path of the file should be `app/src/main/assets/hubspot-info.json`. - Add the HubSpot package to your build gradle file: ```hubl implementation "com.hubspot.mobilechatsdk:mobile-chat-sdk-android::LATEST_VERSION" ``` - [Sync](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Sync.html) your Android project with its gradle files. - Build and run the app. ## Install and configure the SDK The SDK needs to be configured once per app launch. The most convenient time to configure the SDK is during app initialization. Start by getting an instance of the `HubSpotManager` class, then call the `configure` method ```hubl val manager = HubspotManager.getInstance(context) manager.configure() try! HubspotManager.configure() return true } ``` Failure to include the config file, or forgetting to include the file as being part of your apps target will cause initialization to throw an errors. The `HubspotConfigError` class represents different errors when missing properties. ## Open HubSpot chat view The chat view can be opened by `HubspotWebActivity` which extends the `Activity` class. You can open it by using any of the following approaches: - Directly calling `startActivity` via intent - Create any button type, then within an `onClick` listener of that button, open the `HubspotWebActivity`. - Add `HubspotFloatingActionButton` in the file which handle the clicks and open the `HubspotWebActivity` automatically. For example, if you wanted to go with the second approach above and specify the behavior within an `onClick` listener of a button: ```hubl binding.anybutton.setOnClickListener { startActivity(Intent(requireContext(), HubspotWebActivity::class.java)) } ``` ## Identify users with the HubSpot visitor identification token You can identify users by using the visitor identification API, detailed in this article. This API is best implemented in your own server project, where you can pass the identity token to your app based on whether suits your specific setup (i.e., passing a token in response to a visitor going through a login page as a result of a dedicated API that you own). Once a token is generated, it can be associated with a contact's email address by calling `HubspotManager.setUserIdentity(email, identityToken)`. This should be called before opening a chat view. ## Add custom chat data properties The SDK supports setting key-value pairs to keep track of data you might need to track while a chat session is open. You can set your own custom values, or declare common permission preferences such as photo or notification permissions. Use the `HubspotManager.setChatProperties(key, value)` method and provide the associated key and value you want to set. This is best called before starting a chat, and will apply to all new chats. You could set an account status, or other identifiers when setting up your user. These will then appear in all chats opened for the remainder of the app launch. For example, the following code would set permissions for camera, photo, notifications, and location data to `"false"`. ```hubl val keyValuePair = mapOf( ChatPropertyKey.CameraPermissions.chatPropertyValue to "false", ChatPropertyKey.PhotoPermissions.chatPropertyValue to "false", ChatPropertyKey.NotificationPermissions.chatPropertyValue to "false", ChatPropertyKey.LocationPermissions.chatPropertyValue to "false" ) hubspotManager.setChatProperties(keyValuePair) ``` ## Clear data on logout The SDK stores in memory identification tokens, email address, and any properties set. The push token for the app is also associated with the current user, if applicable. You may want to clear this data when a user is logging out, or changing users in a multi user app. To clear this data, call `HubspotManager.logout()` at an appropriate time in in your app. Calling the `HubspotManager.logout()` only impacts the data used for future chat sessions. It has no impact on data or chat sessions already stored in HubSpot. ## Reference documentation You can consult the [reference documentation](https://github.hubspot.com/mobile-chat-sdk-android/) for details on how to use each of the components in the HubSpot mobile SDK. The binary file is also hosted [here](https://search.maven.org/artifact/com.hubspot.mobilechatsdk/mobile-chat-sdk-android/1.0.0/jar). # Integrate the HubSpot mobile chat SDK into your iOS app @ Learn how to use the HubSpot mobile chat SDK in your iOS app. $ guides & api/conversations/mobile-chat-sdk --- # Integrate the HubSpot mobile chat SDK into your iOS app You can use the HubSpot mobile chat SDK to integrate your iOS mobile application with HubSpot's live chat functionality. The mobile chat SDK allows you to: - Integrate HubSpot chat into your mobile app to deliver real-time, in-app customer support. - Leverage the [bot](https://knowledge.hubspot.com/chatflows/create-a-bot) and [knowledge base](https://knowledge.hubspot.com/knowledge-base/create-and-customize-knowledge-base-articles) tools to help deflect customer inquires when your support agents are unavailable. - Alert users of new messages via push notifications. - Customize the chat experience to align with your business's brand and UI. ## Installation To get start developing with the mobile chat SDK: - Add the [GitHub repository URL](https://github.com/HubSpot/mobile-chat-sdk-ios) of the mobile chat SDK to your project using Swift Package Manager. From your project settings, select the **Package Dependencies** tab, then search for the [HubSpot mobile chat SDK GitHub URL](https://github.com/HubSpot/mobile-chat-sdk-ios) to add it to your project. - While this feature is in beta, you may need to configure Xcode with your GitHub account since this repository is private: - To add your GitHub account directly in Xcode, navigate to **Xcode** > **Settings** in the top menu bar, then click **Account**. Click the **\+ icon** to add your GitHub account. - If you're developing your app using a CLI tool like `xcodebuild`, you may need to specify the `-scmProvider system` or `-scmProvider xcode` arguments to choose whether your system git credentials or xcode credentials are used. ## Configuration After you've added the mobile SDK to your project using the Swift Package Manager, include your `HubSpot-Info.plist config` file in your project, then mark it as included in the app target. During app startup, or in another suitable location in your app's code where you initialize your app components, call the configure method on the SDK. ```hubl func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. // This will configure the SDK using the `Hubspot-Info.plist` file that is bundled in app try! HubspotManager.configure() return true } ``` ## Open HubSpot Chat View You can present the chat view modally as a [sheet](https://developer.apple.com/design/human-interface-guidelines/sheets), as a fullscreen view, or pushed into a navigation stack. The simplest way to get started is to present the chat as a sheet in response to a button press in the UI of your app. The chat view can be initialized using the `HubSpotChatView.init(manager:pushData:chatFlow:)` method, using either default values or with customized chat settings. ### Show the chat view as a sheet in SwiftUI The chat view is a SwiftUI View, meaning it can be the contents of a [sheet](https://developer.apple.com/design/human-interface-guidelines/sheets), or embedded in your existing UI like any other view. You can present it as a sheet using the `.sheet` modifier, in response to a user action such as tapping a button. ```hubl Button(action: { showChat.toggle() }, label: { Text("Chat Now") }).sheet(isPresented: $showChat, content: { HubspotChatView(chatFlow: "support") }) ``` In the example above, `$showChat` is a state property in the view: ```hubl @State var showChat = false ``` ### Show the chat as a presented view controller in UIKit Although the HubSpot Chat View is a SwiftUI view, it will also work when contained in a `UIHostingController`. For example, you can present the chat view from a UIViewController button action. ```hubl @IBAction func onButtonPress(_ source: Any) { //Init chat view with no arguments , or use alternative initialiser for configuring chat specifics let chatView = HubspotChatView() //Create a hosting controller to hold the chat view let hostingVC = UIHostingController(rootView: chatView) // Present the view controller like any other (or push into a navigation stack) self.present(hostingVC, animated: true) } ``` ## Identify users with the HubSpot visitor identification token You can identify users by using the visitor identification API, detailed in [this article](/guides/api/conversations/visitor-identification). This API is best implemented in your own server project, where you can pass the identity token to your app based on whether suits your specific setup (i.e., passing a token in response to a visitor going through a login page as a result of a dedicated API that you own). Once a token is generated, it can associated with a contact's email address by calling `HubspotManager/setUserIdentity(identityToken:email:)`. This should be called before opening a chat view. ## Add custom chat data properties The SDK supports setting key-value pairs to keep track of data you might need to track while a chat session is open. You can set your own custom values, or declare common permission preferences such as photo or notification permissions. Use the `HubspotManager/setChatProperties(data:)` method and provide the associated key and value you want to set. This is best called before starting a chat, and will apply to all new chats. You could set an account status, or other identifiers when setting up your user. These will then appear in all chats opened for the remainder of the app launch. For example, the following code would set several pre-defined permissions and custom properties: ```hubl var properties: [String: String] = [ ChatPropertyKey.cameraPermissions.rawValue: self.checkCameraPermissions(), "myapp-install-id": appUniqueId, "subscription-tier": "premium" ] HubspotManager.shared.setChatProperties(data: properties) ``` ## Clearing data on logout The SDK stores in memory identification tokens, email address, and any properties set. The push token for the app is also associated with the current user, if applicable. You may want to clear this data when a user is logging out, or changing users in a multi user app. To clear this data, call `HubspotManager/clearUserData()` at an appropriate time in your app. Calling the `HubspotManager/clearUserData()` only impacts the data used for future chat sessions. It has no impact on data or chat sessions already stored in HubSpot. ## Reference documentation You can consult the [reference documentation](https://github.hubspot.com/mobile-chat-sdk-ios/documentation/hubspotmobilesdk/) for details on how to use each of the components in the HubSpot mobile SDK. # Visitor Identification @ The visitor identification API is used to identify visitors to your site that were authenticated using external authentication systems. $ guides & api/conversations --- # Visitor identification Use the visitor identification API to identify visitors to your site that were authenticated using your own external authentication system. An identification token returned from this API can be used to pass information about your already-authenticated visitor to the chat widget, so that it treats the visitor as a known contact. Agents in the inbox can then have confidence about who they are talking to, and visitors can access previous thread history across devices. For example, if you host your own web app behind a login, you may set up the HubSpot chat widget to appear on pages within your web app where you know that visitors have already been authenticated and identified. Currently, any visitor chatting in on those pages would still show up as “Unknown visitor” in the Conversations inbox, despite being an identified, logged-in visitor in your web app. Using the Visitor Identification API, you can pass authenticated visitor information directly to the chat widget, which identifies them in the Conversations inbox. - The visitor identification API is for telling HubSpot who the visitor is. You should not rely on this to authenticate users in your platform. - Access to the visitor identification API requires a _Professional_ or _Enterprise_ level subscription. If the account does not have a qualifying subscription, you will receive a `403` error response from the API. ## Example integration flow To integrate with this feature, you must have an existing web application with an authentication system. Before getting started, make sure you have a [private app](/guides/apps/private-apps/overview)set up and the account that you are trying to integrate has a qualifying _Professional_ or _Enterprise_ subscription. Here’s an example of a possible integration flow: Once your customer is logged in and verified in your system, take the following steps to identify them within live chat: **1.** On your front end, set `loadImmediately` to `false` on the `hsConversationsSettings` object on the window. If you do not do this, the chat widget may load before the identification information is passed through. See the [Chat Widget SDK primer below](#chat-widget-sdk-primer) for more information. - Set the `hsConversationsSettings` properties outside the `isConversationsAPIReady` function. - In addition, the `hsConversationsSettings` needs to be set prior to the call, otherwise you may experience a race condition that interferes with widget load. ```js window.hsConversationsSettings = { loadImmediately: false, }; ``` **2.** Generate a token from the Visitor Identification API by passing in the email address of your authenticated visitor. This should be done on the back end of your web application. Check out the [endpoints reference documentation](/reference/api/conversations/visitor-identification) for an example request. ```shell curl --request POST \ --url 'https://api.hubspot.com/conversations/v3/visitor-identification/tokens/create \ --data '{ "email": "gob@bluth.com", "firstName": "Gob", "lastName": "Bluth" }' ``` The provided first and last name will be set on the contact record in HubSpot after the chat begins if: - It's a new contact created by the Visitor Identification API. - It's an existing contact where the name is not already known. This can be useful when personalizing messages to identified visitors when your external system already has name information, but it does not yet exist in HubSpot. These are optional parameters and not required. **3.** Using the token Step 2, set the following properties on the `hsConversationsSettings` object on the window. ```js window.hsConversationsSettings = { identificationEmail: 'visitor-email@example.com', identificationToken: 'Congrats on purchasing some of the best ice cream around.
{{custom.productName}} ``` The `customProperties` field only supports arrays when used with [programmable email content](/guides/cms/content/data-driven-content/emails-with-programmable-content). In your email template, you can reference the items defined in your `customProperties` field by using a [HubL expression](/reference/cms/hubl/overview) (e.g., using a [for loop](/reference/cms/hubl/loops) to render each item in a list). For example, if the `customProperties` you included in your request body was structured like the following JSON snippet below: ```json { "emailId": 4126643122, "message": { "to": "jdoe@hubspot.com" "sendId": "7" }, "customProperties": { "exampleArray": [ {"firstKey": "someValue", "secondKey": "anotherValue"}, {"firstKey": "value1", "secondKey": "value2" } ] } } ``` You could then reference the values for each item in `exampleArray` with the following HubL code: ```hublThanks for your recent purchase! Here are the details of the items you'll be receiving:
Congrats on purchasing some of the best ice cream around.
{{custom.productName}} ``` The `customProperties` field only supports arrays when used with [programmable email content](/guides/cms/content/data-driven-content/emails-with-programmable-content). In your email template, you can reference the items defined in your `customProperties` field by using a [HubL expression](/reference/cms/hubl/overview) (e.g., using a [for loop](/reference/cms/hubl/loops) to render each item in a list). For example, if the `customProperties` you included in your request body was structured like the following JSON snippet below: ```json { "emailId": 4126643122, "message": { "to": "jdoe@hubspot.com" "sendId": "7" }, "customProperties": { "exampleArray": [ {"firstKey": "someValue", "secondKey": "anotherValue"}, {"firstKey": "value1", "secondKey": "value2" } ] } } ``` You could then reference the values for each item in `exampleArray` with the following HubL code: ```hublThanks for your recent purchase! Here are the details of the items you'll be receiving:
This is a sample. When viewing source, you should only see the HTML Comment.
HTML Comment Wrapper Start
HTML Comment Wrapper End
HubL Delimiter Comment Wrapper Start
{# This comment is using the HubL Delimiter for comments. These comments appear here but do not render in the front end #}HubL Delimiter Comment Wrapper End
``` ### Templates must load over HTTPS If using third-party files, your listing must be loaded over HTTPS to ensure proper security. Likewise, all code must render properly when being viewed over HTTPS. This is to avoid mixed content warnings in the browser console and make sure all content displays properly. ### Third-party files Third-party files must be loaded on the HubSpot CDN unless they are from a reputable source such as JSDelivr, Google Hosted Libraries, or CDNJS. These files can be added to the stylesheet using the @import feature. If you are including files in a module, you must use the [css_assets](/reference/cms/modules/configuration) and [js_assets](/reference/cms/modules/configuration) parameters in your meta.json file (Linked Files section in Design Tools). This only works with modules in themes, and will not work for standalone modules. ### Template errors All templates must not display any errors in either the Design Tools or the browser console. An example of errors is shown below. ## Module compatibility with themes The `alternate_names` attribute can be used to achieve module compatibility with themes in the Template Marketplace. It provides the bridge for a module to integrate with as many marketplace themes as possible without much effort from providers and module developers. Theme providers define a new attribute called `alternate_names` which contains standard fields mapped to the module fields. Alternate names are supported for fonts and color fields. Module fields will [inherit](/guides/cms/content/fields/overview#inherited-fields) from the standard color and font fields. This is a new attribute introduced for theme fields. For example: ```json { "label": "ButtonColor", "name": "button_color", "type": "color", "visibility": { "hidden_subfields": { "opacity": true } }, "alternate_names": ["primary_color"], "default": { "color": "#516747" } } ``` In the above example, developers get the ability to access the button color in two ways: `theme.button_color` and `theme.primary_color`. This way, providers can update their existing theme to meet template standards. Modules and themes must adhere to the following requirements to ensure functionality when used across themes: - The font and color style fields must follow these standard naming conventions: `primary_color`, `secondary_color`, `heading_font`, and `body_font`. - If theme fields do not have `primary_color`, `secondary_color`, `heading_font`, or `body_font` fields, they can use the `alternate_names` attribute to map existing fields to standard fields. This way, when an independent module is added to the theme template, it has a similar look and feel of the themed module. - A user can [inherit](/guides/cms/content/fields/overview#inherited-fields) either by defining `default_value_path` or `property_value_paths`, or both. Review the code snippet below for an example: - If you use `default_value_path`, the accepted value is `theme.primary_color`. - If you use `property_value_paths` you must use trailing individual properties `.color` or .`opacity` based on the property they are mapping. ```json [ { "id": "d506e41f-7206-bb8f-7fa5-d4a7de75c61e", "name": "color", "display_width": null, "label": "Color", "required": false, "locked": false, "type": "color", "inherited_value": { "default_value_path": "theme.primary_color", "property_value_paths": { "color": "theme.primary_color.color", "opacity": "theme.primary_color.opacity" } }, "default": { "color": "#00FF03", "opacity": 100 } } ] ``` - In the `module.html`, these fields can be referred to with the following dot notation: ```hubl {{ theme.primary_color }}{{ row.name }} | {{ row.cuisine }} |
{{ row.name }} | {{ row.cuisine }} |
{{ row.location['lat'] }}, {{ row.location['lon'] }}
{% else %}{{ row.name }} | {{ row.cuisine }} |
{{ row.location['lat'] }}, {{ row.location['lon'] }}
{% elif request.query_dict['lat'] %}{{ row.name }} | {{ row.cuisine }} | {{ row.location|geo_distance(request.query_dict['lat'], request.query_dict['lon'], "mi")|round(3) }} mi away |
appointment
|
fee
|
quote_template
|
call
|
feedback_submission
|
task
|
cart
|
goal_target
|
tax
|
commerce_payment
|
line_item
|
ticket
|
communication
|
listing
|
partner_client
|
company
|
meeting_event
|
lead
|
contact
|
note
|
service
|
course
|
order
|
subscription
|
deal
|
postal_mail
|
invoice
|
discount
|
product
|
user
|
email
|
quote
|
partner_account
|
engagement
|
appointment
|
fee
|
quote_template
|
call
|
feedback_submission
|
task
|
cart
|
goal_target
|
tax
|
commerce_payment
|
line_item
|
ticket
|
communication
|
listing
|
partner_client
|
company
|
meeting_event
|
lead
|
contact
|
note
|
service
|
course
|
order
|
subscription
|
deal
|
postal_mail
|
invoice
|
discount
|
product
|
user
|
email
|
quote
|
partner_account
|
engagement
|
info
: a blue alert to provide general information.success
: a green alert indicating a positive outcome.warning
: a yellow alert indicating caution.danger
: a red alert indicating a negative outcome.tip
: a white alert to provide guidance.