SalesForce-Einstein Custom Skill

Objective

This guide will help you to quickly connect to SalesForce Einstein and create various methods to pull data. The purpose is to demonstrate how easy it is to integrate SalesForce Einstein to the VoiceWorx platform.

Pre-requisites

  • An active Salesforce Einstein Account

  1. It is required for the user to have an active Salesforce Einstein account as this integration will require login to the users Salesforce account.

If an active account is not established, please follow the steps below:

  1. Go to https://developer.salesforce.com and click on “Signup” button. It should take you to the screen below. Fill out the relevant details and complete the registration process:

  1. Once the registration is complete, go to www.Salesforce.com, login with the credentials and the screen below will appear:

  1. Now Einstein platform will need to be enabled. To do this, go to search bar and search for analytics then click “Getting Started” as shown in picture below:

  1. On the page, click “Enable Einstein Analytics” as shown below:

  1. After Einstein is enabled, click on “Launch Einstein Analytics” button on the same place as shown below:

  1. This will redirect to Einstein platform tab where you can access Dashboards, DataSets, Lenses, Stories, etc. The user is able to execute lenses and perform SAQL queries on datasets from our Salesforce custom skills which will be demonstrated under the method section of the documentation. The landing page of Einstein platform is shown below:

Steps

To proceed with these steps, you should have all the pre-requisites satisfied. If you are missing something, please go back and make sure you satisfy all of them.

Once done, you are ready to get started using VoiceWorx platform with SalesForce.

The following shows the general steps/activities that will be carried out in setting up this integration. Note: It is advisable to use same email for signup across the 3 channels below. Step 1 -3 below are required.

  1. Ensure you Login With Amazon (LWA) https://developer.amazon.com/alexa/console/ask account is setup by your admin. If you are the account admin, you can follow this instruction to set it up.

  2. Set up connection to Salesforce

  3. Create a custom skill in Voiceworx.

  4. Publish the skill

  5. Test the Alexa skill.

Setup connection to Salesforce

  1. Login to the VoiceWorx portal at https://portal.voiceworx.ai. After login, the VoiceWorx portal home page will be shown as below:

  1. To Configure Salesforce, use the left navigation menu and select “Integration” then select "Connect System”.

  1. The user will be redirected to “Connect to External Systems” interface as shown below. Now click “Connect to External Systems” in the lower left corner.

  1. A popup will appear. Please select or enter the following:

Select Integration Category: Custom

Select System Type: SalesForceCustom

System Instance Name: Sales Force Custom

Click: “CONNECT SYSTEM”

Note: If a SalesForce Account is running on customer domain tick “Use Custom Domain” checkbox and provide the custom domain URL. Also, if Sandbox account is used then tick “Sandbox” checkbox.

  1. After clicking “Connect System”, the user will be redirected to “Allow” access page. Click on “Allow” which will take the user to SalesForce login page as shown below.

  1. Once logged in, the user will be redirected to the VoiceWorx platform with a success screen as shown below.

  1. Now, you have successfully integrated Salesforce with the VoiceWorx platform. Now, click on “Return to Integration Configuration” to return to the connections page. SalesforceCustom should now appear in the list as shown below.

Create a custom skill in Voiceworx

  1. To create a skill, use the left navigation menu and select “Custom Skills” then select “Manage Skills” and then click “Create New Custom Skill“. The screen below will appear.

  1. Add Custom Skill by doing the following:

Name: Salesforce Custom Skill

Custom Skill Type: Search

Category: None

Click: Save.

  1. The screen below will appear:

  1. A Data Source connects the Skill with the integration. Once a skill is created, use the tabs at the top and click “Data Sources” then click “Create New Data Source”.

  1. The following popup screen will appear:

  1. Add DataSource by doing the following:

Name: Salesforce DataSource

Integration Configuration: SalesForceCustom : SalesForceCustom@youraccountname

Click: Save

Create Methods to fetch the data from Salesforce

  1. Methods allows you to fetch data from Salesforce.

VoiceWorx platform currently supports following Salesforce methods:

  1. Get All Objects

  2. Get Object Fields

  3. Get Object ById

  4. Get Object All Records

  5. Get SOQL Query Results

  6. Create Object

  7. Update Object

  8. Delete Object

Depending on the user’s requirement, select an appropriate method. This document will explain one method with an example and rest of methods will be on the appendix section.

Create Methods to Fetch the Data from Salesforce

  1. Methods allows you to fetch data from Salesforce.

Currently, VoiceWorx platform supports following Salesforce Einstein methods,

  1. Einstein.ExecuteSAQLQuery

  2. Einstein.ExecuteLens

  3. Einstein.GetAnalyticsResources

  4. Einstein.GetDashboards

  5. Einstein.GetDataSets

  6. Einstein.GetLenses

Depending on the requirement, the appropriate method will need to used. This document will explain one method with an example and rest of methods will be on the appendix section.

Scenario/ Use Case (Explore Opportunities)

  1. Salesforce Einstein lists out opportunities. For this, you can use “Einstein.ExecuteLens” method as explained below.

Use the top menu tabs. Click on the “Methods”.

  1. Click “Create New Methods”. Then select or enter the following:

Name: OpportunitiesByNameMethod

Request Type: Einstein.Executelens

Lens: Explore Opportunities (AppName)

Result Type: ListOfRecords

Record Limit: 10

Record JsonPath: $.results.records[*]

Empty Result Template: No Opportunities Found

Record Templat: {{Name}} with amount {{sum_Amount}}

Result Template: I have found the following opportunities {{Records}}

Click: Save

Create Intents

  1. In the top menu tabs, select “Intents” and “Create New Intent”. Then select or enter the following:

Name: OpportunitiesByNameIntent

Intent Type: Search

Intent Action: Execute Method

DataSource: Salesforce DS

DataSource Method: OpportunitiesByNameMethod

Click: Save

Create Utterance

In the top menu tabs, select “Utterance” and select “Create New Utterance”. Utterance are words spoken to launch specific intents. Now input or select the following:

Value: list opportunities by name

Custom Skill: Salesforce Custom Skill

Intent: OpportunitiesByNameIntent

Click: Save

Create Input

In the top menu tabs, select “Input” and select “Create New Input”. Then input or select the following:

Name: OpportunitiesByNameInput

Custom Skill: Salesforce Custom Skill

Custom Intent: OpportunitiesByNameIntent

Data Source: Salesforce DS

Data Source Method: OpportunitiesByNameMethod

Publish to Alexa

  1. To publish to Alexa, select “Publish” in the top menu tabs then click “Add Skill Publishing”. Then input or select the following:

External Skill Name: Salesforce Einstein Skill. (This will be the name of the skill in Alexa. Therefore, make it unique and different from the names of your other skills in Alexa.)

Skill Type: Search

Channel: Alexa

Skill Invocation Name: salesforce einstein. (This will be what users say to launch your skill in Alexa. It must be in lower case alphabets cannot contain START, BEGIN, STOP, EXIT, LAUNCH and cannot contain number or special characters.)

Uncheck the following: Require account linking, Auto Publish

Optional: Replace all placeholder values in all “Message”. Uncheck all the settings shown in the second image below.

Click: Save.

  1. In the top menu tabs select “Publish” then click “Publish to Alexa”.

Once in Publish Skill to Amazon Alexa select and do the following:

Selected Skill: Contact Finder

Select Amazon Account: LWA Config

Select the LWA account setup by your admin or the one you set up in step 4 above.

Click: Publish To Alexa

  1. On the resulting screen, ensure that a success message shows for the publishing steps before clicking the “Go To Alexa Skill”. If success message not shown, click “Go To Skill Publishing” to fix any issue shown in publishing result.

  1. On the Alexa skill page, ensure “Full Build Successful” message is shown in bottom right corner before starting to test skill.

  1. Go to “test” tab in the top menu, then below “test” tab change the skill test status from “Off” to “Development”.

  1. Invoke skill by typing the invocation name (Salesforce einstein) inserted in the publishing step in Voiceworx. If the invocation is successful, your configured welcome message will be displayed in the developer console.

Congratulations!

You have successfully completed building a SalesForce -Einstein Custom Skill.

Appendix

Salesforce Methods

Method: Einstein.ExecuteSAQLQuery

This method requires parameters as explained below.

Parameters:

Parameter

Sample Value

Info

SAQL Query

q = group q by all;

q = foreach q generate count() as 'count';

q = limit q 2000;

This is a standard Salesforce Analytics query language (SAQL) query which you can use in different ways. You just need to make sure, you need to omit the first line i.e “load dataset {datasetname}” from the query as you can choose the required dataset from the dropown of dataset parameter and system injects that in query by itself.

Datasets

Pipeline Trending (VoiceworxSalesApp)

Choose the required dataset from dropdown you want to execute SAQL query against.

Other than these two parameters, you need to provide following standard inputs:

Parameter

Info

Method Name

You can give any name. This name will be displayed in the methods list.

Request Type

Einstein.ExecuteSAQLQuery

This is the method that you are using

Parameters

As explained in the previous table

Result Type

ListOfRecords (Auto Selected)

It indicates that the method can return one or more records

Record Limit

Numeric value (e.g. 10)

If Method is returning larger number of records, then you can limit this result by providing this value.

Record JsonPath

Each method returns data in json format and to pick any specific information from the json, we need to specify the Record JsonPath so Voice Worx platform will pick that data in consideration while displaying results.

Example: $.results.records[*]

This selects all the records that is returned.

Empty Result Template

When the method does not return any data, this response will be generated. So we can specify something like:

“Sorry, I could not find the data”

Record Template

Let’s assume that the following json represents a record.

{

  • "action" : query,

  • "responseId" : 4ZYb6WZm8DGZp_0fHwqHSV,

  • "results" : -{

    • "metadata" : +[ ... ],

    • "records" : -[

      • -{

        • "Quarter" : This Quarter,

        • "StageName" : Prospecting,

        • "stage_sort" : 1,

        • "sum_Amount" : 24597662,

        • "time_sort" : 1

},

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... }

]

  • },

  • "query" : q = load \"0Fb2w000000HGNMCA4/0Fc2w000002C0f9CAC\";\nq = filter q by 'Stage.IsClosed' == \"false\";\nq = filter q by 'ForecastCategory' != \"Omitted\";\ntoday = filter q by 'IsLastUpdate' == \"1\";\ntoday = group today by 'StageName';\ntoday = foreach today generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 0 as 'time_sort', \"Current\" as 'Quarter';\none = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"1 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"current quarter\"..]);\none = group one by 'StageName';\none = foreach one generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 1 as 'time_sort', \"This Quarter\" as 'Quarter';\ntwo = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"2 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"1 quarter ago\"..]);\ntwo = group two by 'StageName';\ntwo = foreach two generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 2 as 'time_sort', \"1 quarter ago\" as 'Quarter';\nthree = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"3 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"2 quarters ago\"..]);\nthree = group three by 'StageName';\nthree = foreach three generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 3 as 'time_sort', \"2 quarters ago\" as 'Quarter';\nfour = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"4 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"3 quarters ago\"..]);\nfour = group four by 'StageName';\nfour = foreach four generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 4 as 'time_sort', \"3 quarters ago\" as 'Quarter';\nresult = union today, one, two, three, four;\nresult = group result by ('Quarter', 'StageName');\nresult = foreach result generate 'StageName' as 'StageName', 'Quarter' as 'Quarter', sum('sum_Amount') as 'sum_Amount', first('stage_sort') as 'stage_sort', first('time_sort') as 'time_sort';\nresults = order result by ('time_sort' desc, 'stage_sort' asc);,

  • "responseTime" : 114

}

In this example, you want to access the items of records array,

So record template can be written as

{{StageName}}, amount {{sum_Amount}}

Note:

Anything written in between {{ }} is represented as a json field and it’s case-sensitive.

{{StageName}} is not same as {{stagename}}

Result Template

This indicates how method results should be represented.

Here you go, We have found the following historical pipeline by stage, {{Records}}

Here, {{Records}} represents one or more records separated by a separator.

Now the response looks like:

I have found the following historical pipeline by stage, Prospecting, amount 24597662, Qualification, amount 53942843, Needs Analysis, amount 64842060, Value Proposition, amount 29715331, Perception Analysis, amount 38981892, Proposal/Price Quote, amount 15889140, Negotiation/Review, amount 17044891, Prospecting, amount 24597662, Qualification, amount 53942843, Needs Analysis, amount 64842060

Method: Einstein.ExecuteLens

This method requires parameters as explained below.

Parameters:

Parameter

Sample Value

Info

Lens

Historical Pipeline Stage by Quarter (VoiceworxSalesApp)

Choose the required lens from dropdown.

Other than these two parameters, you need to provide following standard inputs

Parameter

Info

Method Name

You can give any name. This name will be displayed in the methods list.

Request Type

Einstein.ExecuteLens

This is the method that you are using

Parameters

As explained in the previous table

Result Type

ListOfRecords (Auto Selected)

It indicates that the method can return one or more records

Record Limit

Numeric value (e.g. 10)

If Method is returning larger number of records, then you can limit this result by providing this value.

Record JsonPath

Each method returns data in json format and to pick any specific information from the json, we need to specify the Record JsonPath so Voice Worx platform will pick that data in consideration while displaying results.

Example: $.results.records[*]

This selects all the records that is returned.

Empty Result Template

When the method does not return any data, this response will be generated. So we can specify something like:

“Sorry, I could not find the data”

Record Template

Let’s assume that the following json represents a record.

{

  • "action" : query,

  • "responseId" : 4ZYb6WZm8DGZp_0fHwqHSV,

  • "results" : -{

    • "metadata" : +[ ... ],

    • "records" : -[

      • -{

        • "Quarter" : This Quarter,

        • "StageName" : Prospecting,

        • "stage_sort" : 1,

        • "sum_Amount" : 24597662,

        • "time_sort" : 1

},

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... },

      • +{ ... }

]

  • },

  • "query" : q = load \"0Fb2w000000HGNMCA4/0Fc2w000002C0f9CAC\";\nq = filter q by 'Stage.IsClosed' == \"false\";\nq = filter q by 'ForecastCategory' != \"Omitted\";\ntoday = filter q by 'IsLastUpdate' == \"1\";\ntoday = group today by 'StageName';\ntoday = foreach today generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 0 as 'time_sort', \"Current\" as 'Quarter';\none = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"1 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"current quarter\"..]);\none = group one by 'StageName';\none = foreach one generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 1 as 'time_sort', \"This Quarter\" as 'Quarter';\ntwo = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"2 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"1 quarter ago\"..]);\ntwo = group two by 'StageName';\ntwo = foreach two generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 2 as 'time_sort', \"1 quarter ago\" as 'Quarter';\nthree = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"3 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"2 quarters ago\"..]);\nthree = group three by 'StageName';\nthree = foreach three generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 3 as 'time_sort', \"2 quarters ago\" as 'Quarter';\nfour = filter q by (date('ValidFromDate_Year', 'ValidFromDate_Month', 'ValidFromDate_Day') in [..\"4 quarters ago\"]) && (date('ValidToDate_Year', 'ValidToDate_Month', 'ValidToDate_Day') in [\"3 quarters ago\"..]);\nfour = group four by 'StageName';\nfour = foreach four generate 'StageName' as 'StageName', sum('Amount') as 'sum_Amount', last('Opportunity.Stage.SortOrder') as 'stage_sort', 4 as 'time_sort', \"3 quarters ago\" as 'Quarter';\nresult = union today, one, two, three, four;\nresult = group result by ('Quarter', 'StageName');\nresult = foreach result generate 'StageName' as 'StageName', 'Quarter' as 'Quarter', sum('sum_Amount') as 'sum_Amount', first('stage_sort') as 'stage_sort', first('time_sort') as 'time_sort';\nresults = order result by ('time_sort' desc, 'stage_sort' asc);,

  • "responseTime" : 114

}

In this example, you want to access the items of records array,

So record template can be written as

{{StageName}}, amount {{sum_Amount}}

Note:

Anything written in between {{ }} is represented as a json field and it’s case-sensitive.

{{StageName}} is not same as {{stagename}}

Result Template

This indicates how method results should be represented.

Here you go, We have found the following historical pipeline by stage, {{Records}}

Here, {{Records}} represents one or more records separated by a separator.

Now the response looks like:

I have found the following historical pipeline by stage, Prospecting, amount 24597662, Qualification, amount 53942843, Needs Analysis, amount 64842060, Value Proposition, amount 29715331, Perception Analysis, amount 38981892, Proposal/Price Quote, amount 15889140, Negotiation/Review, amount 17044891, Prospecting, amount 24597662, Qualification, amount 53942843, Needs Analysis, amount 64842060

Method: Einstein.GetAnalyticsResources

This method is used to fetch all the available analytics resources like datasets,lenses,dashboards,etc.

Parameters:

This method does not require any parameter.

Sample Response:

Contact object has around 61 fields so this method will return you that much records, one record represents one field.

{
 "dashboards": "/services/data/v49.0/wave/dashboards",
 "dataConnectorTypes": "/services/data/v49.0/wave/dataConnectorTypes",
 "dataConnectors": "/services/data/v49.0/wave/dataConnectors",
 "dataflowjobs": "/services/data/v49.0/wave/dataflowjobs",
 "datasets": "/services/data/v49.0/wave/datasets",
 "folders": "/services/data/v49.0/wave/folders",
 "lenses": "/services/data/v49.0/wave/lenses",
 "query": "/services/data/v49.0/wave/query",
 "recipes": "/services/data/v49.0/wave/recipes",
 "replicatedDatasets": "/services/data/v49.0/wave/replicatedDatasets",
 "schedules": "/services/data/v49.0/wave/watchlist/schedules",
 "templates": "/services/data/v49.0/wave/templates",
 "trendedreports": "/services/data/v49.0/wave/trendedreports"
}

Method: Einstein.GetDashboards

This method is used to fetch all the available dashboards that you created in Einstein platform.

Parameters:

This method does not require any parameter.

Sample Response:

{
 "dashboards": [
 {
 "allowPreview": true,
 "assetSharingUrl": "https://ap16.salesforce.com/analytics/wave/dashboard?assetId=0FK2w000000J0fdGAC&orgId=00D2w00000BbXPz&loginHost=ap16.salesforce.com&urlType=sharing",
 "createdBy": {
 "id": "0052w000005ltohAAA",
 "name": "Sandeep Rimal",
 "profilePhotoUrl": "https://c.ap16.content.force.com/profilephoto/005/T"
 },
 "createdDate": "2020-09-04T08:00:54Z",
 "datasets": [
 {
 "id": "0Fb2w000000HGNECA4",
 "label": "Cases",
 "name": "case1",
 "url": "/services/data/v49.0/wave/datasets/0Fb2w000000HGNECA4"
 },

Method: Einstein.GetDatasets

This method is used to fetch all the available datasets that are availabled in your Einstein platform acccount.

Parameters:

This method does not require any parameter.

Sample Response:

{
 "datasets": [
 {
 "clientShardsUrl": "/services/data/v49.0/wave/datasets/0Fb2w000000HGNMCA4/shards",
 "createdBy": {
 "id": "0052w000005ltohAAA",
 "name": "Sandeep Rimal",


 "profilePhotoUrl": "https://c.ap16.content.force.com/profilephoto/005/T"
 },
 "createdDate": "2020-09-04T08:00:50Z",
 "currentVersionId": "0Fc2w000002C0f9CAC",
 "currentVersionUrl": "/services/data/v49.0/wave/datasets/0Fb2w000000HGNMCA4/versions/0Fc2w000002C0f9CAC",
 "dataRefreshDate": "2020-09-04T08:08:56Z",
 "datasetType": "default",
 "folder": {
 "id": "00l2w000000uYhpAAE",
 "label": "VoiceworxSalesApp",
 "name": "VoiceworxSalesApp",
 "url": "/services/data/v49.0/wave/folders/00l2w000000uYhpAAE"
 },
 "id": "0Fb2w000000HGNMCA4",
 "label": "Pipeline Trending",
 "lastAccessedDate": "2020-11-19T12:10:42Z",
 "lastModifiedBy": {
 "id": "0052w000006TsBIAA0",
 "name": "Integration User",
 "profilePhotoUrl": "https://c.ap16.content.force.com/profilephoto/005/T"
 },
 "lastModifiedDate": "2020-09-04T08:08:57Z",
 "lastQueriedDate": "2020-11-19T11:50:00Z",
 "name": "pipeline_trending1",
 "permissions": {
 "create": true,
 "manage": true,
 "modify": true,
 "view": true
 },
 "type": "dataset",
 "url": "/services/data/v49.0/wave/datasets/0Fb2w000000HGNMCA4",
 "versionsUrl": "/services/data/v49.0/wave/datasets/0Fb2w000000HGNMCA4/versions"
 }

Method: Einstein.GetLens

This method is used to fetch all the available lenses that are available in your Einstein platform account.

Parameters:

This method does not require any parameter.

Sample Response:

{
 "lenses": [
 {
 "allowPreview": true,
 "assetSharingUrl": "https://ap16.salesforce.com/analytics/wave/lens?assetId=0FK2w000000J0fYGAS&orgId=00D2w00000BbXPz&loginHost=ap16.salesforce.com&urlType=sharing",
 "createdBy": {
 "id": "0052w000005ltohAAA",
 "name": "Sandeep Rimal",
 "profilePhotoUrl": "https://c.ap16.content.force.com/profilephoto/005/T"
 },
 "createdDate": "2020-09-04T08:00:51Z",
 "datasets": [
 {
 "id": "0Fb2w000000HGNMCA4",
 "name": "pipeline_trending1",
 "url": "/services/data/v49.0/wave/datasets/0Fb2w000000HGNMCA4"
 }
 ],
 "dateVersion": 1,
 "files": [],
 "filesUrl": "/services/data/v49.0/wave/lenses/0FK2w000000J0fYGAS/files",
 "folder": {
 "id": "00l2w000000uYhpAAE",

 "label": "VoiceworxSalesApp",
 "name": "VoiceworxSalesApp",
 "url": "/services/data/v49.0/wave/folders/00l2w000000uYhpAAE"
 },
 "historiesUrl": "/services/data/v49.0/wave/lenses/0FK2w000000J0fYGAS/histories",
 "id": "0FK2w000000J0fYGAS",
 "label": "Historical Pipeline Stage by Quarter",
 "lastAccessedDate": "2020-11-19T12:10:41Z",
 "lastModifiedBy": {
 "id": "0052w000005ltohAAA",
 "name": "Sandeep Rimal",
 "profilePhotoUrl": "https://c.ap16.content.force.com/profilephoto/005/T"
 },
 "lastModifiedDate": "2020-09-04T08:00:51Z",
 "name": "Historical_Pipeline_Stage_By_Quarter1",
 "permissions": {
 "create": true,
 "manage": true,
 "modify": true,
 "view": true
 },
 "refreshDate": "2020-09-04T08:07:48Z",
 "type": "lens",
 "url": "/services/data/v49.0/wave/lenses/0FK2w000000J0fYGAS",
 "visualizationType": "stackvbar"}

Last updated