Salesforce is the leading customer relationship management (CRM) platform. With Salesforce, businesses can manage their sales, marketing, and customer service operations. The Salesforce REST and SOAP APIs allow you to integrate your CRM data with other systems and applications.

Sequin syncs Salesforce to an ordered event stream you can use to easily build your CRM integration, or connect into your customer’s CRM data.

You can build directly on the Sequin stream or forward data to your database, Kafka or any other system you use to store and process data. We’ll handle the authentication, rate limit, and consistency for you.

You’ll create, update, and delete Salesforce objects (e.g. leads, contacts, and accounts) using Sequin’s Collection Mutation API. Sequin simultaneously applies changes to Salesforce and the event stream. Giving you a unified interface to Salesforce.

Here is how our Salesforce sync works:

Sync process

Authentication

You can authenticate with Salesforce in the Sequin Console using OAuth 2. You’ll first enter the subdomain of your Salesforce instance, and then you’ll be redirected to Salesforce to authenticate. Sequin will handle your refresh tokens and keep your connection alive.

You can also authenticate with Salesforce by importing a credential via the Management API:

curl --request POST \
  --url https://api.sequin.io/v1/credentials \
  --header 'Content-Type: application/json' \
  --data '{
    "properties": {
        "instance_url": "https://sequin-dev-ed.my.salesforce.com/",
        "kind": "salesforce",
        "refresh_token": "7eC39HqLyjWDarjtT1zdp7dc",
        "name": Chaom Spice
    },
    "metadata": { "custom_property": 42 }
  }'

Backfill

When you first start a Salesforce sync, Sequin will extract all the data from the Salesforce collections you want to sync. This is called backfilling.

To backfill Salesforce, Sequin make SOQL requests for each object and paginates through the results. This ensures that you get all the data from the Salesforce accoun in your stream.

We’re able to pull 200 records per request. Depending on how much rate limit you allocate to Sequin, the backfill can take a few minutes to a few hours.

Real-time

After the initial backfill, we’ll continuously poll your Salesforce instance to monitor changes. Respecting the rate limit, we’ll round-robin each of the collections you’ve selected to sync.

The latency of your sync is directly related to the rate limit you allocate to Sequin. For instance, if you allocate 100,000 requests / day to Sequin and sync 10 collections, here is the average latency you can expect:

  • 100,000 requests / 24 hours / 60 minutes / 60 seconds = 1.157 requests / second
  • 1.157 requests / second * 10 collections = 11.57 seconds to sync all collections

So the average latency for your sync will be ~12 seconds. That is, it will take at most 12 seconds for a change in Salesforce to appear in your stream.

Pacing

Salesforce has both a rate limit and a concurrency limit.

The rate limit is the number of requests you can make to the Salesforce API in a rolling 24-hour period. Paid Salesforce accounts start with 100,000 requests / 24 hours. Larger enterprise accounts typically have millions of API calls / 24 hours.

As a working default, Sequin will pace your Salesforce sync to 28,800 requests / 24 hours. This is 1 request every 3 seconds and less than 30% of typical account’s API rate limit. You can find your Salesforce rate limit in the Salesforce Setup page under Company Information > API Requests, Last 24 Hours.

You can adjust this rate limit in the Sequin Console or via the Management API.

The concurrency limit is the number of requests you can make to the Salesforce API at the same time. Sequin paces requests to ensure that we don’t exceed the concurrency limit.

Schema

Standard objects

Sequin can sync all Salesforce standard objects and fields. We refer to these as standard collections.

Here are the standard collections we support. If there is a standard object you need that isn’t listed, just send us a message and we’ll add it for you in a day or two.

  • Account
  • AccountContactRelation
  • Asset
  • Attachment
  • Campaign
  • CampaignMember
  • CampaignMemberStatus
  • Case
  • CaseHistory
  • Contact
  • ContentDocument
  • ContentNote
  • Contract
  • Event
  • Lead
  • Note
  • Opportunity
  • OpportunityContactRole
  • OpportunityFieldHistory
  • OpportunityHistory
  • OpportunityLineItem
  • OpportunityStage
  • Opportunity__hd
  • Order
  • OrderItem
  • Pricebook2
  • PricebookEntry
  • Product2
  • Profile
  • RecordType
  • Task
  • User
  • UserRole
  • WorkOrder

Custom objects and fields

Sequin also supports Salesforce custom objects and fields. We refer to these as custom collections.

Any custom object or field you create in Salesforce will be available to sync with Sequin.

When you want to sync a custom field within a standard object, the standard object will now sync as a custom collection and include the custom field.

For instance, if you want to sync a custom field custom_field__c within the lead object, you’ll now setup your sync to include the lead custom collection and the custom_field__c custom field.

Because custom collections are unique to a specific Salesforce instance and credential, you’ll need to setup your custom collections on a sync-by-sync basis. You can do this in the Sequin Console or via the Management API using the list custom collections endpoint.

Streams

Your Salesforce sync will now populate data into the record and event streams. Here’s how Sequin structures Salesforce objects in the stream:

Record stream

The record stream contains the current state of an object in Salesforce. For instance, you’ll see the current state of a contact as it exists in Salesforce:

{
  "collection_id": "salesforce:contact",
  "deleted": false,
  "id": "2bf6e25e-c70b-4ed9-9801-e46d852b050d",
  "inserted_at": "2024-02-06T20:48:35.776148Z",
  "payload": {
    "FirstName": "Duncan",
    "MasterRecordId": null,
    "today__c": "2024-02-06",
    "LastReferencedDate": "2024-02-06T20:48:34.000+0000",
    "AccountId": null,
    "IndividualId": null,
    "Salutation": null,
    "OtherAddress": null,
    "LastName": "Idaho",
    "OtherGeocodeAccuracy": null,
    "OtherStreet": null,
    "MailingLongitude": null,
    "EmailBouncedReason": null,
    "Fax": null,
    "Description": null,
    "Level__c": null,
    "MailingStreet": null,
    "ReportsToId": null,
    "MailingGeocodeAccuracy": null,
    "OtherCountry": null,
    "External_ID__c": null,
    "Birthdate": null,
    "LastCURequestDate": null,
    "IsEmailBounced": false,
    "MailingPostalCode": null,
    "OtherPostalCode": null,
    "LeadSource": null,
    "AssistantName": null,
    "MailingCity": null,
    "CleanStatus": "Pending",
    "Name": "Duncan Idaho",
    "Jigsaw": null,
    "attributes": {
      "type": "Contact",
      "url": "/services/data/v54.0/sobjects/Contact/0038b00003HqJL3AAN"
    },
    "LastModifiedById": "0058b00000GgeA2AAJ",
    "JigsawContactId": null,
    "OtherState": null,
    "CreatedById": "0058b00000GgeA2AAJ",
    "Languages__c": null,
    "IsDeleted": false,
    "Department": null,
    "OtherLongitude": null,
    "OtherLatitude": null,
    "CreatedDate": "2024-02-06T20:48:32.000+0000",
    "Email": "idaho@sequin.io",
    "MailingAddress": null,
    "MailingState": null,
    "OwnerId": "0058b00000GgeA2AAJ",
    "testtest__c": null,
    "LastModifiedDate": "2024-02-06T20:48:32.000+0000",
    "MailingLatitude": null,
    "OtherPhone": null,
    "LastActivityDate": null,
    "MailingCountry": null,
    "OtherCity": null,
    "Phone": null,
    "HomePhone": null,
    "Title": null,
    "MobilePhone": null,
    "testtestt__c": null,
    "Id": "0038b00003HqJL3AAN",
    "reports_to_name__c": null,
    "PhotoUrl": "/services/images/photo/0038b00003HqJL3AAN",
    "LastViewedDate": "2024-02-06T20:48:34.000+0000",
    "LastCUUpdateDate": null,
    "EmailBouncedDate": null,
    "AssistantPhone": null,
    "SystemModstamp": "2024-02-06T20:48:32.000+0000"
  },
  "payload_hash": "P7YB6KjXUiNOPdrQZBgSIg==",
  "resource_id": "0fedc477-2976-4d17-9058-23c86d6efc2c",
  "updated_at": "2024-02-06T20:48:35.776148Z",
  "upsert_opts": null,
  "upstream_id": "0038b00003HqJL3AAN",
  "upstream_updated_at": "2024-02-06T20:48:32.000000Z"
}

Event stream

The event stream contains the changes to an object in Salesforce. As an example, if the FirstName and LastName of a contact object is updated, the event stream will contain the following event:

{
  "changes": {
    "FirstName": "Duncan",
    "LastModifiedDate": "2024-02-06T20:48:32.000+0000",
    "LastName": "Idaho",
    "LastReferencedDate": "2024-02-06T20:48:34.000+0000",
    "LastViewedDate": "2024-02-06T20:48:34.000+0000",
    "Name": "Duncan Idaho",
    "SystemModstamp": "2024-02-06T20:48:32.000+0000"
  },
  "collection_id": "salesforce:contact",
  "created_at": "2024-02-06T20:50:14.877945Z",
  "data": {
    "FirstName": "Paul",
    "MasterRecordId": null,
    "today__c": "2024-02-06",
    "LastReferencedDate": "2024-02-06T20:50:05.000+0000",
    "AccountId": null,
    "IndividualId": null,
    "Salutation": null,
    "OtherAddress": null,
    "LastName": "Atreides",
    "OtherGeocodeAccuracy": null,
    "OtherStreet": null,
    "MailingLongitude": null,
    "EmailBouncedReason": null,
    "Fax": null,
    "Description": null,
    "Level__c": null,
    "MailingStreet": null,
    "ReportsToId": null,
    "MailingGeocodeAccuracy": null,
    "OtherCountry": null,
    "External_ID__c": null,
    "Birthdate": null,
    "LastCURequestDate": null,
    "IsEmailBounced": false,
    "MailingPostalCode": null,
    "OtherPostalCode": null,
    "LeadSource": null,
    "AssistantName": null,
    "MailingCity": null,
    "CleanStatus": "Pending",
    "Name": "Paul Atreides",
    "Jigsaw": null,
    "attributes": {
      "type": "Contact",
      "url": "/services/data/v54.0/sobjects/Contact/0038b00003HqJL3AAN"
    },
    "LastModifiedById": "0058b00000GgeA2AAJ",
    "JigsawContactId": null,
    "OtherState": null,
    "CreatedById": "0058b00000GgeA2AAJ",
    "Languages__c": null,
    "IsDeleted": false,
    "Department": null,
    "OtherLongitude": null,
    "OtherLatitude": null,
    "CreatedDate": "2024-02-06T20:48:32.000+0000",
    "Email": "idaho@sequin.io",
    "MailingAddress": null,
    "MailingState": null,
    "OwnerId": "0058b00000GgeA2AAJ",
    "testtest__c": null,
    "LastModifiedDate": "2024-02-06T20:50:05.000+0000",
    "MailingLatitude": null,
    "OtherPhone": null,
    "LastActivityDate": null,
    "MailingCountry": null,
    "OtherCity": null,
    "Phone": null,
    "HomePhone": null,
    "Title": null,
    "MobilePhone": null,
    "testtestt__c": null,
    "Id": "0038b00003HqJL3AAN",
    "reports_to_name__c": null,
    "PhotoUrl": "/services/images/photo/0038b00003HqJL3AAN",
    "LastViewedDate": "2024-02-06T20:50:05.000+0000",
    "LastCUUpdateDate": null,
    "EmailBouncedDate": null,
    "AssistantPhone": null,
    "SystemModstamp": "2024-02-06T20:50:05.000+0000"
  },
  "event_type": "updated",
  "id": "40886d95-dee6-48de-bef6-3196a01a4a7d",
  "resource_id": "0fedc477-2976-4d17-9058-23c86d6efc2c",
  "upstream_id": "0038b00003HqJL3AAN",
  "upstream_updated_at": "2024-02-06T20:50:05.000000Z"
}

Consumers

You can build directly on Sequin’s stream using the stream APIs. Or forward data to your database, Kafka or any other system you use to store and process data.

Salesforce syncs work with all the consumers Sequin supports.

Mutations

When you need to create, update, or delete a Salesforce object, you can use Sequin’s Collection Mutation API. For instance, if you want to create a contact in Salesforce, you’ll use the create mutation:

curl -X POST \
  https://api.sequin.io/v1/mutations/run/create \
  -H 'content-type: application/json' \
  -d '{
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "data": [
          {
            "FirstName": "Paul",
            "LastName": "Atreides",
            "Email": "paul@arrakis.org"
          }
        ]
      }'

Sequin will handle the authentication, rate limit, and consistency for the request by simultaneously applying changes to Salesforce and the event stream. As an added consistency guarantee, you can also specify which consumers you want to await before returning the mutation response.

For instance, you can ensure that a new contact has been added to your database before the the API returns a 200 OK.

Development

Sequin works with Salesforce’s development tools so you can easily test your integration before moving it to production.

Salesforce provides two types of development environments:

  1. Developer accounts: These are free Salesforce accounts that you can use to build and test your integration. You’ll need to manually replicate your production data model in your dev account.
  2. Sandboxes: These are full or partial copies of your production Salesforce account purpose-built for replicating your production data for testing and development. Sandboxes aren’t included in all Salesforce plans, but are available for purchase.

Both developer accounts and sandboxes have a unique subdomain. You’ll use this subdomain to authenticate with Sequin - and the sync will work the same as with your production account.

Once you’ve tested your integration, you can use the Management API to easily replicate your sync to your production account.