This article showcases how to use Content Builder API in Salesforce Marketing Cloud.
Before we start
First and foremost, we need to define what Content Builder actually is and what kind of API (application programming interface) it uses.
Content Builder is what we call a DAM (Digital Asset Management) integrated as one of the core applications in Salesforce Marketing Cloud for cross-channel asset management.
Content Builder API, however, refers to the REST API implementation in Marketing Cloud that targets specifically the assets (images, documents, emails, content blocks, etc…).
Therefore, the following code snippets and recommendations concern exclusively the use of REST API for the Content Builder and its many asset types.
HTTP requests
HTTP requests are the bread and butter of REST API. They allow us to communicate with the Content Builder and perform the CRUD operations.
Server-side JavaScript methods
In server-side JavaScript, there are 2 possible methods of performing HTTP requests: Core and Script Utility Object.
Core example
var request = HTTP.Post(
endpoint,
"application/json",
Stringify(payload),
["Authorization"],
["Bearer " + accessToken]
);
var result = request.Response;
Script Utility Object example
var request = new Script.Util.HttpRequest(endpoint);
request.emptyContentHandling = 0;
request.retries = 2;
request.continueOnError = true;
request.setHeader("Authorization", "Bearer " + accessToken);
request.method = "POST";
request.contentType = "application/json";
request.postData = Stringify(payload);
var results = request.send();
var status = results.statusCode;
var result = Platform.Function.ParseJSON(String(results.content));
Choosing one or the other depends on the requirements of our code.
Core method is shorter to write, fast to remember and the response object doesn’t require parsing, but it only provides POST and GET request methods and lacks the flexibility of defining the number of retries, encoding or providing a better error handling.
Moreover, performing POST and GET requests with the Core method will return the results in a different sub-object:
HTTP.Get() response
{
Status: 0,
Content: {
...
}
}
HTTP.Post() response
{
Status: 0,
Response: {
...
}
}
As for the Status property, here are all the possible values returned by the Core method:
Value | Meaning |
0 | Status is OK |
-1 | Missing URL |
-2 | HTTP request error |
-3 | No content returned |
POST and GET requests
Now that we learned about the methods of HTTP requests in server-side JavaScript, let’s have a closer look at the different types of requests and their caveats.
POST requests
POST requests, generally speaking, are a type of the HTTP requests, used to create a new resource.
For example, to create a new folder or upload a new image.
But, in Marketing Cloud, a POST request can also perform an advanced search! Something that is traditionally done with a GET request.
Example
var payload = {
page: {
page: 1,
pageSize: 50
},
query: {
property: "assetType.id",
simpleOperator: "IN",
value: ["20", "21", "22", "23", "28"]
},
sort: [
{
property: "id",
direction: "ASC"
}
],
fields: [
"thumbnail",
"category",
"content",
"data"
]
}
var endpoint = restInstanceUrl + "asset/v1/content/assets/query";
var request = HTTP.Post(
endpoint,
"application/json",
Stringify(payload),
["Authorization"],
["Bearer " + accessToken]
);
var result = request.Response;
Note that passing the parameters in the request is matter of compiling the data in a well organised object and passing it as a string to the HTTP method.
In the example above, the query filter is based on the asset ids (read full list), which exist for every type of asset in the Content Builder.
Here is the id mapping for the most used web image formats.
Id | Name |
20 | gif |
21 | jpe |
22 | jpeg |
23 | jpg |
28 | png |
GET requests
GET requests, on the other hand, do exactly as designed: retrieve assets from the Content Builder!
But Marketing Cloud wouldn’t be Marketing Cloud if there wasn’t a catch: passing the parameters in these requests is somewhat unorthodox and require a specific syntax.
Traditionally, adding parameters to a GET request is a matter of concatenating them at the end of the endpoint, in the same manner as we would do for the URL parameters.
https://mydomain.com/api/post?size=50&order=asc
Content Builder API, on the other hand, prefixes each parameter with a $ symbol and uses keywords, simple quotes and spaces to create filters.
GET parameters
$page | Number of the page to retrieve. Starts with 1. |
$pagesize | Number of results to return by request. |
$orderBy | Name of the field and the direction of sorting. |
$fields | Comma-separated field names to include in the response. |
$filter | Simple condition for filtering the result of the query. |
GET filter operators
eq | Equals. Compares numbers and strings. |
neq | Is not equal to. Compares numbers and strings. |
lt | Is less than. Compares numbers only. |
lte | Is less than or equal to. Compares numbers only. |
gt | Is greater than. Compares numbers only. |
gte | Is greater than or equal to. Compares numbers only. |
like | Is similar to. Compares strings only. |
Examples
/asset/v1/content/categories?$pagesize=20&$filter=parentId eq 3916
/asset/v1/content/assets?$filter=Name%20like%20'hello%20world'
Note that both empty spaces and URL encoded space %20
both work, but it’s best practice to always encode special characters in the URL.
GET responses
What about the responses? Are there any caveats? Of course there are!
In Content Builder API, GET requests return an parsable object in 99% of cases (as far as I know), except for the file binary retrieval.
Request
var id = "123456";
var endpoint = restInstanceUrl + "asset/v1/content/assets/" + id + "/file";
var request = HTTP.Get(endpoint, ["Authorization"], ["Bearer " + accessToken]);
var result = request.Content;
Response
"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACB..."
Why? Because of reasons!
Note that when using Script Utility Object to perform the request, there is no longer any need to parse the JSON object from the response:
Platform.Function.ParseJSON(String(results.content))
PATCH and PUT requests
In a regular API, PATCH requests are used to partially update a resource and a PUT request replaces the target completely.
In Marketing Cloud, again, not everything is by the book.
Sending PATCH requests to update assets is a breeze, but for whatever reason, updating the category of an asset (folder) requires the usage of the PUT request.
var id = 123456;
var payload = {
Id: 123456,
Name: "Updated Folder Name",
ParentId: 78912345,
CategoryType: "asset"
};
var endpoint = restInstanceUrl + "asset/v1/content/categories/" + id;
var request = new Script.Util.HttpRequest(endpoint);
request.emptyContentHandling = 0;
request.retries = 2;
request.continueOnError = true;
request.setHeader("Authorization", "Bearer " + accessToken);
request.method = "PUT";
request.contentType = "application/json";
request.postData = Stringify(payload);
var results = request.send();
var result = Platform.Function.ParseJSON(String(results.content));
DELETE request
And finally, let’s talk about the most dangerous API method: DELETE request.
When performing this request using the asset ID, the deletion from the Content Builder is permanent. Or is it?
The short answer is: NOT!
In order to permanently delete the asset, we need to provide an extra parameter at the and of the endpoint: isCDNDelete=1
var id = "123456";
var endpoint = restInstanceUrl + "asset/v1/content/assets/" + id + "?isCdnDelete=1";
var request = new Script.Util.HttpRequest(endpoint);
request.emptyContentHandling = 0;
request.retries = 2;
request.continueOnError = true;
request.setHeader("Authorization", "Bearer " + accessToken);
request.method = "DELETE";
request.contentType = "application/json";
var results = request.send();
var result = results.statusCode;
What happens if we don’t? The public URL of the asset remains available and accessible to the users (official documentation).
This, of course, only concerns the assets with public URLs, such as images and documents. As for the blocks and such, they are gone forever!
If you want to avoid permanently deleting files, please use the archive endpoint.
Conclusion
Using Content Builder API is a challenging endeavour. Hopefully this article helps you out on your Marketing Cloud journey of discovery and provides a much needed explanation where the documentation is lacking.
Want to learn more REST API methods? Jump to my new documentation website!
Good luck out there and be golden!
Have I missed anything?
Please poke me with a sharp comment below or use the contact form.