This article explains how to create new records in a Data Extension using Async API in Salesforce Marketing Cloud.
Insert methods
In server-side JavasScript, there are 3 well known methods for inserting or upserting new records in a Data Extension: Platform, Core and WSProxy.
But, what about the REST? (get it?)
As a matter of fact, Marketing Cloud REST API offers a small range of methods for working with Data Extension records.
They are divided in 2 categories: asynchronous and synchronous. What’s the difference? Let’s find out!
Async vs sync
The terms asynchronous and synchronous are nothing new in the web development and are mostly used in the context of AJAX (Asynchronous JavaScript) requests.
Asynchronous (or Async for short) refers to the type of requests that are performed and then queued in the background, while the rest of our code can work on something else.
Synchronous requests on the other hand, stop the processing of our code and wait for the response before it can continue on further tasks.
Why use async methods?
There are many advantages of using async methods in server-side JavaScript.
Here are some of them:
- No records are lost when Marketing Cloud servers are unavailable.
- Processing is faster, as the code doesn’t need to wait for Marketing Cloud to finish inserting new records.
- Error handling that gives a clear message when an error occurs and doesn’t prevent the rest of the code from executing.
Sounds perfect, but what’s the catch? Well… there are several drawbacks that we need to be aware of:
- Async requests are managed with REST API, which requires a token to be generated and preferably stored.
- We can only queue 5MB of data per request, which means that large sets of data need to be split in several parts and processed sequentially.
- The status and the result of the call need to be performed separately with more REST API requests.
Now that we know what the async requests are and why we would want to use them, let’s try it out!
Before we start
For starters, let’s create a Data Extension with the CustomerKey (or External Key) “S0M3-GU1D-K3Y-G03SR1G4T-H3R3” and the following fields:
Field name | Primary Key | Type | Length |
SubscriberKey | Yes | Text | 50 |
FirstName | No | Text | 50 |
LastName | No | Text | 80 |
EmailAddress | No | 256 |
As a second step, we also need the knowledge of how to perform a REST API request and how to store the token. Please refer to my previous article on that matter.
Let’s code!
Insert or upsert a new record
At first, we need to define the records as an array of objects, set as a value of the key “items” in a parent object:
{
items: [
{
SubscriberKey: GUID(),
FirstName: "John",
LastName: "Doe",
EmailAddress: "example@mail.com"
},
{
SubscriberKey: GUID(),
FirstName: "Jane",
LastName: "Doe",
EmailAddress: "example@mail.com"
}
]
}
Then, pass the object we just created as the body (or payload) of the request and perform a POST REST API call to this endpoint, where the CustomerKey of our Data Extension is referenced:
/data/v1/async/dataextensions/key:S0M3-GU1D-K3Y-G03SR1G4T-H3R3/rows
Example request
<script runat="server">
Platform.Load("core", "1");
var api = new Script.Util.WSProxy();
var restInstanceUrl = "https://YOUR_SUBDOMAIN.rest.marketingcloudapis.com/",
accessToken = "YOUR_REST_API_TOKEN";
try {
var customerKey = "S0M3-GU1D-K3Y-G03SR1G4T-H3R3";
var payload = {
items: [
{
SubscriberKey: GUID(),
FirstName: "John",
LastName: "Doe",
EmailAddress: "example@mail.com"
},
{
SubscriberKey: GUID(),
FirstName: "Jane",
LastName: "Doe",
EmailAddress: "example@mail.com"
}
]
}
var endpoint = restInstanceUrl + "data/v1/async/dataextensions/key:" + customerKey + "/rows";
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.encoding = "UTF-8";
request.postData = Stringify(payload);
var results = request.send();
var result = Platform.Function.ParseJSON(String(results.content));
Write(Stringify(result));
} catch(error) {
Write(Stringify(error));
}
</script>
Note that the method of the request is important: a POST request will insert and a PUT request will upsert a record in a Data Extension.
Example result
Here is the result of the request when no errors have occurred:
{
"requestId": "S0M3-GU1D-K3Y-1SR1G4T-H3R3",
"resultMessages": [
]
}
Check the status
In order to check the status, we need to use the requestId we received as a result from the insert request in the following endpoint:
/data/v1/async/S0M3-GU1D-K3Y-1SR1G4T-H3R3/status
Example request
<script runat="server">
Platform.Load("core", "1");
var api = new Script.Util.WSProxy();
var restInstanceUrl = "https://YOUR_SUBDOMAIN.rest.marketingcloudapis.com/",
accessToken = "YOUR_REST_API_TOKEN";
try {
var requestId = "S0M3-GU1D-K3Y-1SR1G4T-H3R3";
var endpoint = restInstanceUrl + "data/v1/async/" + requestId + "/status";
var request = new Script.Util.HttpRequest(endpoint);
request.emptyContentHandling = 0;
request.retries = 2;
request.continueOnError = true;
request.setHeader("Authorization", "Bearer " + accessToken);
request.method = "GET";
request.contentType = "application/json";
request.encoding = "UTF-8";
var results = request.send();
var result = Platform.Function.ParseJSON(String(results.content));
Write(Stringify(result));
} catch(error) {
Write(Stringify(error));
}
</script>
Example result
The result has all the useful information we possibly need about our ongoing request.
{
"status": {
"callDateTime": "2023-02-20T15:00:00.00",
"completionDateTime": "2023-02-20T15:01:00.00",
"hasErrors": false,
"pickupDateTime": "2023-02-20T15:00:30.00",
"requestStatus": "Complete",
"resultStatus": "OK",
"requestId": "S0M3-GU1D-K3Y-1SR1G4T-H3R3"
},
"requestId": "S0M3-GU1D-K3Y-C4NB-H3R3"
}
Retrieve the results
Retrieving the results of the request works in the same manner as retrieving the status.
/data/v1/async/S0M3-GU1D-K3Y-1SR1G4T-H3R3/results
Example request
<script runat="server">
Platform.Load("core", "1");
var api = new Script.Util.WSProxy();
var restInstanceUrl = "https://YOUR_SUBDOMAIN.rest.marketingcloudapis.com/",
accessToken = "YOUR_REST_API_TOKEN";
try {
var requestId = "S0M3-GU1D-K3Y-1SR1G4T-H3R3";
var endpoint = restInstanceUrl + "data/v1/async/" + requestId + "/results";
var request = new Script.Util.HttpRequest(endpoint);
request.emptyContentHandling = 0;
request.retries = 2;
request.continueOnError = true;
request.setHeader("Authorization", "Bearer " + accessToken);
request.method = "GET";
request.contentType = "application/json";
request.encoding = "UTF-8";
var results = request.send();
var result = Platform.Function.ParseJSON(String(results.content));
Write(Stringify(result));
} catch(error) {
Write(Stringify(error));
}
</script>
Example result
{
"page": 1,
"pageSize": 50,
"count": 1,
"items": [
{
"errorCode": "UnexpectedError",
"message": "Expect the unexpected!",
"status": "Error"
}
],
"requestId": "S0M3-GU1D-K3Y-C4NB-H3R3"
}
Conclusion
That’s it folks! You now have all the tools to try it for yourself!
Using Async API for inserting or upserting records in Data Extensions is certainly more complicated , but when done right have many valuable advantages that outweigh the drawbacks.
Notes
Before testing out the code snippets, please don’t forget to replace these pieces of text with your own values:
- YOUR_SUBDOMAIN
- YOUR_REST_API_TOKEN
Have I missed anything?
Please poke me with a sharp comment below or use the contact form.