Salesforce Outbound Events to a Private Endpoint Using Skooh (Pattern)
Receive Salesforce outbound messages and Platform Events at internal endpoints.
Overview
Salesforce offers several ways to send events to external systems:
- Outbound Messages (Workflow Rules / Flow)
- Platform Events (with external subscription)
- Change Data Capture
This guide shows the pattern for receiving these at internal endpoints via Skooh.
The Challenge
Salesforce outbound features require a public HTTPS endpoint. Your internal systems don't have one.
Solution: Salesforce → Skooh (public) → Skooh Proxy (internal) → Your service
Setup
1. Create Skooh Endpoint
Create "Salesforce Events" in Skooh.
2. Run the Skooh Proxy
Using the Desktop App:
- Download the Skooh Desktop App
- Enter your API key and hook token
- Set forwarding URL (e.g., `http://localhost:8080/events\`)
- Click Connect
Using Docker:
docker run -d \\
--name skooh-salesforce \\
-e SKOOH_TOKEN=salesforce-events \\
-e SKOOH_API_KEY=your_api_key \\
-e FORWARD_URL=http://salesforce-receiver:8080/events \\
--restart unless-stopped \\
skooh/proxy
Pattern 1: Outbound Messages
Outbound Messages send SOAP XML when records change.
Note: Salesforce's setup varies by edition. See Salesforce Outbound Messages documentation for your specific configuration.
Salesforce Setup
- Create Outbound Message: Setup → Outbound Messages → New
- Endpoint URL: Your Skooh URL
- Select Fields to send
- Create Workflow Rule or Flow to trigger it
Handling SOAP Messages
const xml2js = require('xml2js');
app.post('/events', express.text({ type: 'text/xml' }), async (req, res) => {
const parser = new xml2js.Parser();
const result = await parser.parseStringPromise(req.body);
// Extract notification
const notification = result['soapenv:Envelope']['soapenv:Body'][0]
['notifications'][0]['Notification'][0];
const sobject = notification['sObject'][0];
const recordId = sobject['sf:Id'][0];
// Process the record change
await processRecordChange(sobject);
// Salesforce expects ACK response
res.set('Content-Type', 'text/xml');
res.send(\`<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<notificationsResponse xmlns="http://soap.sforce.com/2005/09/outbound">
<Ack>true</Ack>
</notificationsResponse>
</soapenv:Body>
</soapenv:Envelope>\`);
});
Pattern 2: Platform Events via HTTP
For Platform Events, you can use a lightweight relay:
- Create a Salesforce Function or Heroku app that subscribes to Platform Events
- Forward events to your Skooh URL as JSON
// Salesforce relay service (runs in Salesforce ecosystem)
const jsforce = require('jsforce');
const axios = require('axios');
const conn = new jsforce.Connection({ /* auth */ });
conn.streaming.topic('/event/MyPlatformEvent__e').subscribe(async (event) => {
await axios.post('https://api.skooh.io/hook/salesforce-events', {
eventType: 'MyPlatformEvent__e',
payload: event.payload,
replayId: event.event.replayId
});
});
Pattern 3: Change Data Capture
Similar to Platform Events—subscribe and relay:
conn.streaming.topic('/data/AccountChangeEvent').subscribe(async (event) => {
await axios.post('https://api.skooh.io/hook/salesforce-events', {
eventType: 'AccountChangeEvent',
changeType: event.payload.ChangeEventHeader.changeType,
recordIds: event.payload.ChangeEventHeader.recordIds,
changedFields: event.payload.ChangeEventHeader.changedFields,
payload: event.payload
});
});
Handling Events Internally
app.post('/events', express.json(), async (req, res) => {
const { eventType, payload, changeType } = req.body;
switch (eventType) {
case 'AccountChangeEvent':
await handleAccountChange(payload, changeType);
break;
case 'OpportunityChangeEvent':
await handleOpportunityChange(payload, changeType);
break;
case 'MyPlatformEvent__e':
await handleCustomEvent(payload);
break;
}
res.status(200).send('OK');
});
Resources
Written by Skooh Team