LoopFour

Salesforce

CRM integration for accounts, contacts, opportunities, and custom objects

Salesforce

Connect to Salesforce for comprehensive CRM automation including accounts, contacts, leads, opportunities, and custom objects.

Overview

Salesforce is the world's leading CRM platform. The integration supports:

  • Accounts - Company/organization records
  • Contacts - Individual contact records
  • Leads - Potential customer leads
  • Opportunities - Sales deals and pipeline
  • Tasks - Activities and to-dos
  • Custom Objects - Any sObject type
  • SOQL/SOSL Queries - Custom queries and search

Prerequisites

  • Salesforce account (any edition with API access)
  • Connected App configured for OAuth
  • Appropriate user permissions for API access

Authentication

Salesforce uses OAuth 2.0 for authentication via Nango.

curl "http://localhost:3000/api/v1/connections/salesforce/auth-url" \
  -H "x-api-key: YOUR_API_KEY"

Required Scopes

ScopeDescription
apiREST API access
refresh_tokenOffline access

Available Actions

Account Actions

getAccount

Get an account by ID.

{
  "action": "salesforce.getAccount",
  "config": {
    "accountId": "001xxx"
  }
}

createAccount

Create a new account.

{
  "id": "create-account",
  "type": "action",
  "action": "salesforce.createAccount",
  "config": {
    "name": "{{input.companyName}}",
    "industry": "{{input.industry}}",
    "website": "{{input.website}}",
    "phone": "{{input.phone}}",
    "billingStreet": "{{input.address.street}}",
    "billingCity": "{{input.address.city}}",
    "billingState": "{{input.address.state}}",
    "billingPostalCode": "{{input.address.zip}}",
    "billingCountry": "{{input.address.country}}",
    "type": "Customer",
    "description": "Created via workflow",
    "annualRevenue": "{{input.revenue}}",
    "numberOfEmployees": "{{input.employees}}"
  }
}

Parameters:

FieldTypeRequiredDescription
namestringYesAccount name
industrystringNoIndustry picklist value
websitestringNoWebsite URL
phonestringNoPhone number
billingStreetstringNoBilling street
billingCitystringNoBilling city
billingStatestringNoBilling state
billingPostalCodestringNoBilling postal code
billingCountrystringNoBilling country
typestringNoAccount type
descriptionstringNoDescription
annualRevenuenumberNoAnnual revenue
numberOfEmployeesnumberNoEmployee count

updateAccount

Update an existing account.

{
  "action": "salesforce.updateAccount",
  "config": {
    "accountId": "{{input.accountId}}",
    "website": "{{input.newWebsite}}",
    "type": "Customer"
  }
}

deleteAccount

Delete an account.

{
  "action": "salesforce.deleteAccount",
  "config": {
    "accountId": "{{input.accountId}}"
  }
}

listAccounts

List accounts with filters.

{
  "action": "salesforce.listAccounts",
  "config": {
    "industry": "Technology",
    "type": "Customer",
    "name": "Acme",
    "createdAfter": "2024-01-01T00:00:00Z",
    "orderBy": "CreatedDate",
    "orderDirection": "DESC",
    "limit": 100,
    "offset": 0,
    "fields": ["Id", "Name", "Website", "Industry"]
  }
}

searchAccounts

Full-text search using SOSL.

{
  "action": "salesforce.searchAccounts",
  "config": {
    "searchTerm": "Acme Corporation",
    "industry": "Technology",
    "limit": 25,
    "fields": ["Id", "Name", "Website", "Phone"]
  }
}

Contact Actions

getContact

Get a contact by ID.

{
  "action": "salesforce.getContact",
  "config": {
    "contactId": "003xxx"
  }
}

createContact

Create a new contact.

{
  "id": "create-contact",
  "type": "action",
  "action": "salesforce.createContact",
  "config": {
    "firstName": "{{input.firstName}}",
    "lastName": "{{input.lastName}}",
    "email": "{{input.email}}",
    "phone": "{{input.phone}}",
    "mobilePhone": "{{input.mobile}}",
    "title": "{{input.jobTitle}}",
    "department": "{{input.department}}",
    "accountId": "{{steps.account.output.id}}",
    "mailingStreet": "{{input.address.street}}",
    "mailingCity": "{{input.address.city}}",
    "mailingState": "{{input.address.state}}",
    "mailingPostalCode": "{{input.address.zip}}",
    "mailingCountry": "{{input.address.country}}",
    "description": "Created via workflow"
  }
}

updateContact / deleteContact

{
  "action": "salesforce.updateContact",
  "config": {
    "contactId": "{{input.contactId}}",
    "email": "{{input.newEmail}}"
  }
}

Lead Actions

getLead

Get a lead by ID.

{
  "action": "salesforce.getLead",
  "config": {
    "leadId": "00Qxxx"
  }
}

createLead

Create a new lead.

{
  "id": "create-lead",
  "type": "action",
  "action": "salesforce.createLead",
  "config": {
    "firstName": "{{input.firstName}}",
    "lastName": "{{input.lastName}}",
    "company": "{{input.company}}",
    "email": "{{input.email}}",
    "phone": "{{input.phone}}",
    "title": "{{input.title}}",
    "industry": "{{input.industry}}",
    "status": "New",
    "leadSource": "{{input.source}}",
    "website": "{{input.website}}",
    "description": "{{input.notes}}"
  }
}

Parameters:

FieldTypeRequiredDescription
firstNamestringNoFirst name
lastNamestringYesLast name
companystringYesCompany name
emailstringNoEmail address
phonestringNoPhone number
titlestringNoJob title
industrystringNoIndustry
statusstringNoLead status (default: New)
leadSourcestringNoLead source
websitestringNoWebsite URL
descriptionstringNoDescription

updateLead / deleteLead

{
  "action": "salesforce.updateLead",
  "config": {
    "leadId": "{{input.leadId}}",
    "status": "Qualified"
  }
}

convertLead

Convert a lead to account/contact/opportunity.

{
  "action": "salesforce.convertLead",
  "config": {
    "leadId": "{{input.leadId}}",
    "convertedStatus": "Closed - Converted",
    "doNotCreateOpportunity": false,
    "opportunityName": "{{input.opportunityName}}"
  }
}

Opportunity Actions

getOpportunity

Get an opportunity by ID.

{
  "action": "salesforce.getOpportunity",
  "config": {
    "opportunityId": "006xxx"
  }
}

createOpportunity

Create a new opportunity.

{
  "id": "create-opportunity",
  "type": "action",
  "action": "salesforce.createOpportunity",
  "config": {
    "name": "{{input.dealName}}",
    "accountId": "{{steps.account.output.id}}",
    "stageName": "Prospecting",
    "closeDate": "{{input.expectedCloseDate}}",
    "amount": "{{input.dealValue}}",
    "probability": 20,
    "type": "New Business",
    "leadSource": "{{input.source}}",
    "description": "{{input.notes}}",
    "nextStep": "Initial call scheduled"
  }
}

Parameters:

FieldTypeRequiredDescription
namestringYesOpportunity name
accountIdstringNoAssociated account ID
stageNamestringYesStage name
closeDatestringYesExpected close date (YYYY-MM-DD)
amountnumberNoDeal amount
probabilitynumberNoWin probability (0-100)
typestringNoOpportunity type
leadSourcestringNoLead source
nextStepstringNoNext step description
descriptionstringNoDescription

updateOpportunity

Update an opportunity.

{
  "action": "salesforce.updateOpportunity",
  "config": {
    "opportunityId": "{{input.opportunityId}}",
    "stageName": "Negotiation",
    "amount": "{{input.newAmount}}",
    "probability": 75
  }
}

closeOpportunity

Close an opportunity as Won or Lost.

{
  "action": "salesforce.closeOpportunity",
  "config": {
    "opportunityId": "{{input.opportunityId}}",
    "won": true,
    "amount": "{{input.finalAmount}}",
    "closeDate": "{{now | date: 'YYYY-MM-DD'}}",
    "reason": "Competitive pricing and features"
  }
}

listOpportunities

List opportunities with filters.

{
  "action": "salesforce.listOpportunities",
  "config": {
    "accountId": "{{input.accountId}}",
    "stageName": "Negotiation",
    "isClosed": false,
    "closeDateAfter": "2024-01-01",
    "closeDateBefore": "2024-12-31",
    "minAmount": 10000,
    "orderBy": "Amount",
    "orderDirection": "DESC",
    "limit": 50
  }
}

Task Actions

getTask

Get a task by ID.

{
  "action": "salesforce.getTask",
  "config": {
    "taskId": "00Txxx"
  }
}

createTask

Create a new task.

{
  "id": "create-task",
  "type": "action",
  "action": "salesforce.createTask",
  "config": {
    "subject": "Follow up on proposal",
    "status": "Not Started",
    "priority": "High",
    "whoId": "{{steps.contact.output.id}}",
    "whatId": "{{steps.opportunity.output.id}}",
    "activityDate": "{{input.dueDate}}",
    "description": "Review proposal and schedule call",
    "type": "Call"
  }
}

updateTask / deleteTask

{
  "action": "salesforce.updateTask",
  "config": {
    "taskId": "{{input.taskId}}",
    "status": "Completed"
  }
}

Query Actions

query

Execute a SOQL query.

{
  "action": "salesforce.query",
  "config": {
    "query": "SELECT Id, Name, Industry, Website FROM Account WHERE Industry = 'Technology' AND CreatedDate = THIS_YEAR ORDER BY CreatedDate DESC LIMIT 100"
  }
}

Execute a SOSL search.

{
  "action": "salesforce.search",
  "config": {
    "search": "FIND {Acme} IN ALL FIELDS RETURNING Account(Id, Name, Website), Contact(Id, Name, Email)"
  }
}

Generic sObject Actions

Work with any Salesforce object type.

getRecord

{
  "action": "salesforce.getRecord",
  "config": {
    "sObjectType": "Custom_Object__c",
    "recordId": "a0Bxxx",
    "fields": ["Id", "Name", "Custom_Field__c"]
  }
}

createRecord

{
  "action": "salesforce.createRecord",
  "config": {
    "sObjectType": "Custom_Object__c",
    "data": {
      "Name": "{{input.name}}",
      "Custom_Field__c": "{{input.value}}"
    }
  }
}

updateRecord / deleteRecord

{
  "action": "salesforce.updateRecord",
  "config": {
    "sObjectType": "Custom_Object__c",
    "recordId": "{{input.recordId}}",
    "data": {
      "Custom_Field__c": "{{input.newValue}}"
    }
  }
}

Webhook Triggers

Salesforce events can trigger workflows via outbound messages or Change Data Capture.

{
  "trigger": {
    "type": "webhook",
    "provider": "salesforce",
    "events": ["Account", "Contact", "Opportunity"]
  }
}

Event Types: Account, Contact, Lead, Opportunity, Task, Case, or any custom object

Example Workflow

Lead qualification workflow:

{
  "name": "Lead Qualification",
  "trigger": {
    "type": "webhook",
    "provider": "salesforce",
    "events": ["Lead"]
  },
  "steps": [
    {
      "id": "check-score",
      "type": "condition",
      "config": {
        "conditions": {
          "left": "{{input.payload.Lead_Score__c}}",
          "operator": "gte",
          "right": 80
        },
        "then": ["qualify-lead"],
        "else": ["nurture-lead"]
      }
    },
    {
      "id": "qualify-lead",
      "type": "action",
      "action": "salesforce.updateLead",
      "config": {
        "leadId": "{{input.payload.Id}}",
        "status": "Qualified"
      }
    },
    {
      "id": "create-task",
      "type": "action",
      "action": "salesforce.createTask",
      "config": {
        "subject": "Follow up with qualified lead",
        "whoId": "{{input.payload.Id}}",
        "priority": "High",
        "activityDate": "{{now | dateAdd: 1, 'day' | date: 'YYYY-MM-DD'}}"
      }
    },
    {
      "id": "nurture-lead",
      "type": "action",
      "action": "salesforce.updateLead",
      "config": {
        "leadId": "{{input.payload.Id}}",
        "status": "Working - Contacted"
      }
    }
  ]
}

Rate Limits

LimitValue
API calls per dayBased on edition
Concurrent API limit25 (per user)
Bulk API10,000 records per batch
Query results2,000 records per request

Troubleshooting

Common Errors

ErrorCauseSolution
INVALID_SESSION_IDToken expiredRefresh OAuth connection
REQUIRED_FIELD_MISSINGMissing required fieldCheck field requirements
DUPLICATE_VALUEDuplicate external IDUse upsert or check existing
ENTITY_IS_DELETEDRecord was deletedVerify record exists
INSUFFICIENT_ACCESSMissing permissionsCheck user profile permissions

Field API Names

Salesforce uses API names (e.g., FirstName, Custom_Field__c) rather than labels. Custom fields end with __c.