Skip to content
This repository has been archived by the owner on May 28, 2019. It is now read-only.

symphonyoss/App-Integrations-Salesforce

Repository files navigation

Symphony Software Foundation - Incubating Build Status Dependencies Validation Status codecov

These informations cover only Salesforce specific webhook configuration and the rendering pipeline. For more information about Webhook Integration architecture, development environment, application bootstraping and building, please visit https://github.com/symphonyoss/App-Integrations-Zapier.

Salesforce WebHook Integration

The Salesforce WebHook Integration will allow you to receive notifications in Symphony when a Salesforce opportunity, account or an executive dashboard changes state.

How it works

Unlike JIRA and GitHub, Salesforce does not provide out-of-the-box Webhook support. As such, while in beta, Symphony provides directly to customers an unmanaged package consisting of an Apex trigger and configuration object to achieve this functionality. As a Salesforce administrator, you can configure the unmanaged packaged with the webhook URL generated by the Salesforce Application available in the Symphony Market. You’ll then start receiving notifications for opportunity updates. Symphony will later distribute this integration through a managed Salesforce package.

What formats and events it support and what it produces

Every integration will receive a message sent in a specific format (depending on the system it ingests) and will usually convert it into an internal format before it reaches the Symphony platform. It will also, usually, identify the kind of message based on an "event" identifier, which varies based on the third-party system.

Currently we support the following one event from Salesforce: opportunity notification. Each one can be enabled when configuring your WebHook in the Salesforce system configuration. Below we will detail one event as an example. This example has the JSON payload sent by Salesforce's webhook, the Message ML v2 and EntityJSON generated by the Integration Bridge, and how the message is rendered on Symphony.

An Example: Opportunity Notification

Here we will show a sample payload of an opportunity notification on Salesforce, with the received payload, the MessageML generated by the Integration Bridge, and the message as it is rendered in Symphony.

Message sent from Salesforce webhook
{
  "previous": {
    "opportunity": {
      "Type": "New Customer",
      "StageName": "Proposal/Price Quote",
      "Probability": "75%",
      "Name": "Old Opportunity Test",
      "CloseDate": "2015-02-12T00:00:00.000Z",
      "Account": {
        "Link": "https://link.to.the.opportunity.at.salesforce/path/the/opportunity/at/salesforce",
        "Name": "Opportunity plc",
        "Id": "00856003404oPCeAAM"
      }
    }
  },
  "current": {
    "opportunity": {
      "LastModifiedBy": {
        "Email": "Cassiano.Repache@symphony.com",
        "Name": "Cassiano Cesar Repache",
        "Id": "00578000000ZJrdAAG"
      },
      "Account": {
        "Link": "https://link.to.the.opportunity.at.salesforce/path/to/the/opportunity/at/salesforce",
        "Name": "Test Account",
        "Id": "00146000344oPCcAAM"
      },
      "Owner": {
        "Email": "rsanchez@symphony.com",
        "Name": "Robson Sanchez",
        "Id": "00546000000ZJrdAAG"
      },
      "TotalOpportunityQuantity": null,
      "Probability": "90%",
      "NextStep": "",
      "Amount": 1000.00,
      "StageName": "Negotiation/Review",
      "Type": "Existing Customer - Downgrade",
      "CurrencyIsoCode": "EUR",
      "CloseDate": "2015-02-05 08:00:00T00:00:00.000Z",
      "Link": "https://link.to.the.opportunity.at.salesforce/path/to/the/opportunity/at/salesforce",
      "Name": "New Opportunity Test",
      "Id": "00646002303IyLaAAK"
    }
  }
}
Generated Symphony Message and Json entity (MessageML V2)

When the Integration Bridge posts messages through the Agent that has version equal or greater than '1.46.0' the generated Symphony Message must follow the MessageML V2 specification.

More information about MessageML V2 specification can be accessed here

This is the messageML v2 that the Salesforce integration generates after parsing, which defines the layout of the card and how the front end will render it within Symphony:

<messageML>
    <div class="entity" data-entity-id="OpportunityNotification">
        <card class="barStyle" accent="tempo-bg-color--green" iconSrc="${entity['OpportunityNotification'].current.opportunity.URLIconIntegration}">
            <header>
                <img src="${entity['OpportunityNotification'].current.opportunity.IconCrown}" class="icon" />
                <span class="tempo-text-color--secondary">Opportunity: </span>
                <a class="tempo-text-color--link" href="${entity['OpportunityNotification'].current.opportunity.Link}">${entity['OpportunityNotification'].current.opportunity.Name}</a>
                <span class="tempo-text-color--green"> - ${entity['OpportunityNotification'].current.opportunity.CreatedOrUpdated}</span>
                <span>${entity['OpportunityNotification'].current.opportunity.UpdatedFields}</span>
            </header>
            <body>
                <div>
                    <span class="tempo-text-color--secondary">Account Name:</span>
                    <#if (entity['OpportunityNotification'].current.opportunity.Account.Link)??>
                        <a class="tempo-text-color--link" href="${entity['OpportunityNotification'].current.opportunity.Account.Link}">${entity['OpportunityNotification'].current.opportunity.Account.Name}</a>
                    <#else>
                        <span>${entity['OpportunityNotification'].current.opportunity.Account.Name}</span>
                    </#if>
                </div>
                <br/>
                <div>
                    <span class="tempo-text-color--secondary">Opportunity Owner:</span>
		    <#if (entity['OpportunityNotification'].current.opportunity.Owner.hasOwnerAtSymphony == "true")>
                        <mention email="${entity['OpportunityNotification'].current.opportunity.Owner.Email}" />
                    <#else>
                        <span>${entity['OpportunityNotification'].current.opportunity.Owner.Name} - ${entity['OpportunityNotification'].current.opportunity.Owner.Email}</span>
                    </#if>
                </div>
                <br/>
                <div>
                    <span class="tempo-text-color--secondary">Amount:</span>
                    <span>${entity['OpportunityNotification'].current.opportunity.Amount} - ${entity['OpportunityNotification'].current.opportunity.CurrencyIsoCode}</span>
                </div>
                <br/>
                <div>
                    <span class="tempo-text-color--secondary">Next Step:</span>
                    <span>${entity['OpportunityNotification'].current.opportunity.CloseDate}</span>
                </div>
                <br/>
                <div>
                    <span class="tempo-text-color--secondary">Type:</span>
                    <span>${entity['OpportunityNotification'].current.opportunity.Type}</span>
                </div>
                <hr/>
                <div>
                    <span class="tempo-text-color--secondary">Close Date:</span>
                    <span>${entity['OpportunityNotification'].current.opportunity.CloseDate}</span>
                    <span class="tempo-text-color--secondary">Probability:</span>
                    <span>${entity['OpportunityNotification'].current.opportunity.Probability}</span>
                    <span class="tempo-text-color--secondary">Stage:</span>
                    <span class="tempo-text-color--white tempo-bg-color--yellow tempo-token">${entity['OpportunityNotification'].current.opportunity.StageName}</span>
                </div>
            </body>
        </card>
    </div>
</messageML>

This is the EntityJSON that the Salesforce integration generates after parsing, which defines the content of the card that the front-end will use in combination with the MessageML v2 to render the card:

{  
   "OpportunityNotification":{  
      "type":"com.symphony.integration.salesforce.event.v2.OpportunityNotification",
      "version":"1.0",
      "current":{  
         "type":"com.symphony.integration.salesforce.current",
         "version":"1.0",
         "opportunity":{  
            "type":"opportunity",
            "version":"1.0",
            "Name":"New Opportunity Test",
            "Type":"Existing Customer - Downgrade",
            "Link":"https://link.to.the.opportunity.at.salesforce/path/to/the/opportunity/at/salesforce",
            "NextStep":"-",
            "StageName":"Negotiation/Review",
            "CloseDate":"2015-02-05",
            "Probability":"90%",
            "Amount":"1,000.00",
            "CurrencyIsoCode":"EUR",
            "UpdatedFields":"type, stage, probability, name, close date, account",
            "CreatedOrUpdated":"Updated",
            "URLIconIntegration":"https://nexus2.symphony.com/apps/salesforce/img/salesforce.svg",
            "IconCrown":"https://nexus2.symphony.com/apps/salesforce/img/new_opportunity.svg",
            "LastModifiedBy":{  
               "type":"com.symphony.integration.salesforce.LastModifiedBy",
               "version":"1.0",
               "Name":"Cassiano Cesar Repache",
               "Email":"Cassiano.Repache@symphony.com"
            },
            "Account":{  
               "type":"com.symphony.integration.salesforce.Account",
               "version":"1.0",
               "Name":"Test Account",
               "Link":"https://link.to.the.opportunity.at.salesforce/path/to/the/opportunity/at/salesforce"
            },
            "Owner":{  
               "type":"com.symphony.integration.salesforce.Owner",
               "version":"1.0",
               "Name":"Robson Sanchez",
               "Email":"rsanchez@symphony.com",
	       "hasOwnerAtSymphony": "true"
            }
         }
      }
   }
}
Message rendered on Symphony

Opportunity

Messages color mapping

Salesforce currently only supports opportunity notification. The flair color (vertical bar on the left) will be always green for this event. This can change as we support more events.