Creating a Targeted Campaign Using the Wave API | Salesforce Developers Blog

You probably know that Wave is a great way to explore your Salesforce data in ways that standard analytics can’t. If you haven’t used Wave yet, you should, because it’s awesome.

If you’re using Wave, then you know the power of the query engine, but you might not know about how to leverage the Wave API to use that data programmatically. You can change objects within Salesforce based on insights you find in Wave. This is an extremely powerful way to use Wave and Salesforce together, and in this blog post we’ll show you how to do that.

Converting Contacts into Leads using Wave

A common use case in Wave is analyzing accounts for lead conversion. For example, a marketing team may want to drill down into a set of accounts which they want to target as leads for a new campaign.

Wave allows you to set a myriad of filters on an Account dataset which reveals a list of accounts that are ripe for a new marketing campaign. This is where the Wave API comes in – once the desired list of accounts has been found, the API can be used to extract this list out of Wave and into Salesforce. Once within Salesforce, we can use Apex to manipulate the data however we want.

For the example use case, we’d write some Apex code to take the Account IDs coming from Wave, retrieve the primary contacts of each of these Accounts, and then insert them into a chosen Campaign.

Here are the steps to tackle such a solution:

Step 1: Create a Query in Wave

The first thing you need to do is create a query that drills into the contacts you want to find. In Wave you can do this query in a number of ways, such as retrieving it from a lens, or getting it from a specific step on a dashboard. Here, we’re going to create the query manually.

For this example, we’ll filter Accounts which are in the “Southwest” region with an annual revenue of over 50 Million. A SAQL query to get these results can be defined like so:

q = load "Accounts"; 
q = filter q by 'Region' in ["Southwest"];
q = filter q by 'Annual_Revenue' > 50000000;
q = foreach q generate 'Id' as 'Id';

This query will return all the IDs of Accounts within the desired constraints. A POST to the query endpoint (/services/data/v37.0/wave/query) with this body can be sent to the engine:

    "query":"q = load \"0Fbxx0000000006CAA/0Fcxx000000001dCAA\";
     q = filter q by 'Region' in [\"Southwest\"];
     q = filter q by 'Annual_Revenue' > 50000000;
     q = foreach q generate 'Id' as 'Id';"

The entire query implementation in Apex would look like this:

    //Generic POST request method
    global static string makePostRequest(string endpoint, Map body){
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://' + getWaveURL() + endpoint);
        req.setHeader('Authorization', 'Bearer ' + getSessionID());
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        res = http.send(req);
        return res.getBody();

    //method to send the actual query
    global static string getQueryResults(string queryString){
        Map queryBody = new Map();
        queryBody.put('query', queryString);
        string results = makeRequest('query', queryBody);
        return results;

    string stringResult = getQueryResults(queryString); //Calling function to send query

Step 2: Getting the Contact IDs for the Accounts

In order to get the primary Contact for each account, we need to parse the result that was returned from  the getQueryResults method. The result was as a string, which can be deserialized using the Apex method JSON.deserializeUntyped to:

    "results": {
      "query":"q = load \"0Fbxx0000000006CAA/0Fcxx000000001dCAA\";
               q = filter q by 'Region' in ["Southwest"];
               q = filter q by 'Annual_Revenue' > 50000000;
               q = foreach q generate 'Id' as 'Id';",

The primary contacts of each of IDs of the returned Accounts can now be retrieved. This can be done by by first creating an array of the Account IDs from the JSON result above and then passing this into a SOQL query to get the AccountContactRoles object. From the AccountContactRoles we are then able to get the actual Contacts tied to the Accounts:

//accountIdsArray = ["00561000000QnSR", "00561000000Q3A3", "0056100003wDE31", "0056100032DFEEW"];
List<contactRoles> = [SELECT Id, ContactId FROM AccountContactRole WHERE (AccountId = :accountIdsArray AND isPrimary = true)]; //returns primary AccountContactRole for each Account

List contacts = [SELECT Name, FirstName, LastName, Title, Phone, Email, AccountId FROM Contact WHERE Id = :contactIds]; //returns the actual primary Contact for each Account

Step 3: Insert Contacts into the Campaign

Finally, let’s get these Contacts inserted into the desired Campaign. This can be done by first creating a Lead object from the Contact, and then associating the lead to a Campaign using the CampaignMember object:

        for(Contact c: contacts){
            if (!existingEmails.contains(c.Email)){
                Lead tempLead = new Lead();                        //create new Lead with Contact
                tempLead.FirstName = c.FirstName;                  //information
                tempLead.LastName = c.LastName;
                tempLead.Title = c.Title;
                tempLead.Company = findCompanyName(accounts, c.AccountId);
                tempLead.Phone = c.Phone;
                tempLead.Email = c.Email;
                insert tempLead;

                CampaignMember campaignMem = new CampaignMember();    //create new CampaignMember linked 
                campaignMem.LeadId = tempLead.Id;                     //to the created Lead and the
                campaignMem.campaignId = campaignId;                  //desired Campaign
                insert campaignMem;


This is just one out of the many ways that Wave query engine can be leveraged to perform actions within your Salesforce objects. The process can be generalized to perform any desired business logic once the results are narrowed down by a specific set of filters in the Wave engine. There are other ways to use the Wave API, and look for future blog posts on the subject.

About the Author

Tomasz Bacewicz is a Senior Consultant dedicated to providing solutions in accelerating & optimizing implementation of Wave. Tomasz is a member of the Analytics Cloud’s ASG team.

About the Advanced Solutions Group

A specialized analytics team in the Analytics Cloud product organization that provides world-class technical leadership and guidance focused on empowering the Wave ecosystem. ASG helps drive rapid value by leveraging deep technical knowledge of the Wave platform and apps.

Stay up to date with the latest news from the Salesforce Developers Blog