If you're a developer working in a B2B environment, you know the pain. Your team lives in a specialized tool—let's call it CatalystFlow for this guide—to manage projects, proposals, or technical assets. But the sales and success teams live in Salesforce. The result? A constant, soul-crushing cycle of manual data entry, context switching, and out-of-sync information.
Low-code tools like Zapier are great for simple triggers, but what if you need more control? What if you need to handle complex data mapping, custom logic, or bidirectional syncs? That's when you roll up your sleeves and connect the APIs directly.
This guide will walk you through building a robust, server-side integration between CatalystFlow and Salesforce. We'll ditch the black boxes and give you the ultimate control over your B2B workflow automation.
Why Build a Custom Integration?
- Total Control: Implement custom logic that low-code tools can't handle. Map fields exactly how you want, transform data on the fly, and handle complex business rules.
- Deeper Integration: Go beyond simple "if this, then that." You can create, read, update, and delete records, creating a true two-way sync.
- Scalability & Reliability: Build a solution that can handle high-volume data without hitting task limits or paying per-transaction fees.
- Cost-Effective: A self-hosted script or serverless function can be significantly cheaper at scale than a premium subscription for an integration platform.
The Game Plan: A Webhook-Powered Bridge
Our architecture will be straightforward. CatalystFlow will fire a webhook whenever a key event occurs (e.g., a new project is created). A small middleware service that we build will catch this webhook, process the data, and then use the Salesforce REST API to create or update a record.
Prerequisites
- Salesforce Developer Account: A free sandbox to play in without messing up production data.
- Salesforce Connected App: We'll set this up to get our API credentials.
- CatalystFlow API Key: Your secret key to authenticate with CatalystFlow (if you need to pull data).
- Node.js Environment: We'll use JavaScript, Node.js, and Express for our middleware.
- Basic API Knowledge: You should be comfortable with concepts like REST, JSON, and HTTP requests.
Step 1: Configure Salesforce for API Access
First, we need to tell Salesforce that our external application is allowed to talk to it. We do this by creating a "Connected App."
- In your Salesforce setup, search for App Manager and click New Connected App.
- Fill in the basic information (App Name, your email).
- Check Enable OAuth Settings.
- In the Callback URL, add a placeholder like
http://localhost:3000/oauth2/callback. - For Selected OAuth Scopes, add Access and manage your data (api) and Perform requests on your behalf at any time (refresh_token, offline_access).
- Click Save. It may take a few minutes to activate.
Once it's saved, you'll see a Consumer Key (your client_id) and a Consumer Secret (your client_secret). Keep these safe!
Step 2: Authenticating with Salesforce
For a server-to-server integration, the OAuth 2.0 Username-Password flow is the simplest way to get an access token. Note: This flow should only be used in secure, server-side environments where you can protect your credentials.
Here’s a Node.js function using axios to get your access token.
const axios = require('axios');
const qs = require('qs');
const SF_LOGIN_URL = 'https://login.salesforce.com'; // Use test.salesforce.com for sandboxes
const SF_USERNAME = process.env.SF_USERNAME;
const SF_PASSWORD = process.env.SF_PASSWORD + process.env.SF_SECURITY_TOKEN;
const SF_CLIENT_ID = process.env.SF_CLIENT_ID; // Your Consumer Key
const SF_CLIENT_SECRET = process.env.SF_CLIENT_SECRET; // Your Consumer Secret
async function getSalesforceAccessToken() {
const requestBody = {
grant_type: 'password',
client_id: SF_CLIENT_ID,
client_secret: SF_CLIENT_SECRET,
username: SF_USERNAME,
password: SF_PASSWORD,
};
try {
const response = await axios.post(
`${SF_LOGIN_URL}/services/oauth2/token`,
qs.stringify(requestBody),
{
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}
);
console.log('Successfully fetched Salesforce token!');
return {
accessToken: response.data.access_token,
instanceUrl: response.data.instance_url
};
} catch (error) {
console.error('Error getting Salesforce token:', error.response?.data || error.message);
throw new Error('Could not authenticate with Salesforce.');
}
}
This function returns both the accessToken you'll need for subsequent requests and the instanceUrl, which is the specific base URL for your Salesforce org.
Step 3: Building the Middleware Bridge
Now for the fun part. We'll set up a simple Express server to listen for webhooks from CatalystFlow.
Use Case: Sync New CatalystFlow Projects to Salesforce Opportunities
Let's say when a new project is created in CatalystFlow, we want to automatically create a corresponding Opportunity in Salesforce.
CatalystFlow will send a POST request to our endpoint with a JSON payload like this:
{
"event": "project.created",
"data": {
"projectId": "proj_123xyz",
"projectName": "New Website Build for Acme Corp",
"accountName": "Acme Corp",
"value": 50000,
"closeDate": "2024-12-31"
}
}
Our Express server will catch this, map the fields, and create the Salesforce record.
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
// This function creates the Opportunity in Salesforce
async function createSalesforceOpportunity(projectData, auth) {
const { instanceUrl, accessToken } = auth;
const opportunityPayload = {
Name: projectData.projectName,
AccountId: '0015j00000abcde', // You'd need a way to look up the Account ID
Amount: projectData.value,
StageName: 'Prospecting',
CloseDate: projectData.closeDate,
};
try {
const response = await axios.post(
`${instanceUrl}/services/data/v58.0/sobjects/Opportunity/`,
opportunityPayload,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
}
);
console.log('Successfully created Opportunity:', response.data.id);
return response.data;
} catch (error) {
console.error('Error creating Salesforce Opportunity:', error.response?.data);
throw error;
}
}
// The webhook endpoint
app.post('/webhook/catalystflow', async (req, res) => {
const { event, data } = req.body;
if (event === 'project.created') {
console.log(`Processing new project: ${data.projectName}`);
try {
// 1. Get a fresh token
const sfAuth = await getSalesforceAccessToken();
// 2. Create the record
await createSalesforceOpportunity(data, sfAuth);
res.status(200).send('Webhook processed successfully.');
} catch (error) {
console.error('Failed to process webhook.');
res.status(500).send('Internal Server Error');
}
} else {
res.status(200).send('Event not relevant.');
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
In this code:
- We define an endpoint
/webhook/catalystflowthat accepts POST requests. - It checks if the event is
project.created. - It authenticates with Salesforce to get a fresh token.
- It calls
createSalesforceOpportunityto make the API request, mapping fields from the webhook payload to the SalesforceOpportunityobject. - It includes basic logging and error handling.
Note on AccountId: In a real-world scenario, you wouldn't hardcode the AccountId. You'd first make a SOQL query to the Salesforce API to find the correct Account ID based on accountName from the payload.
Taking It Further
This is a solid foundation for powerful B2B workflow automation. From here, you can:
- Improve Error Handling: Implement a retry mechanism for failed API calls.
- Add More Events: Handle
project.updatedorproject.closedevents to keep Salesforce perfectly in sync. - Build a Two-Way Sync: Use Salesforce's Outbound Messages or Apex Triggers to send data back to CatalystFlow when an Opportunity stage changes.
- Cache the Access Token: Store the Salesforce access token and reuse it until it expires instead of fetching a new one for every request.
By connecting APIs directly, you move beyond the limitations of pre-built connectors and build a system that is perfectly tailored to your team's workflow. Happy coding!
Originally published at https://getmichaelai.com/blog/a-practical-guide-integrating-your-product-with-salesforce-t
Top comments (0)