Your Salesforce Integrations Are Broken.
Here is Exactly Why and How to Fix Them
After 15 years building enterprise integrations, I still see architects and developers default to REST APIs for everything. Here is why that is costing you scalability, reliability, and money. And exactly when to use each pattern.
APIs, Platform Events, and Webhooks are three fundamentally different integration patterns, not interchangeable terms. APIs are synchronous one-to-one conversations. Platform Events are asynchronous one-to-many broadcasts inside Salesforce. Webhooks are outbound push notifications to external systems. Choosing the wrong pattern is the #1 cause of brittle, unscalable Salesforce integrations. This guide explains all three with real-world analogies, architecture diagrams, and a decision framework you can use today.
In This Article
Here is a scenario I encounter on almost every enterprise Salesforce engagement. A new opportunity is closed-won in Salesforce. The ERP needs to be notified to kick off fulfilment. The architect says: “We’ll call the ERP API when the record is saved.” Simple. Done. Except three months later, the ERP team is drowning in duplicate orders during peak load, the Salesforce org has an 8-second save time for Opportunity records, and no one can explain why 3% of orders silently failed.
The technology was correct. The pattern was wrong.
Over 60% of Salesforce integration issues (performance degradation, data loss, duplicate processing, governor limit breaches) trace back to a single root cause: using a synchronous API call where an asynchronous event-driven pattern was needed, or vice versa. The fix is almost never rewriting code. It is changing the architectural pattern.
The three patterns we cover in this article (Salesforce APIs, Platform Events, and Webhooks) are not just different technologies. They represent fundamentally different philosophies about how systems communicate, who is responsible for delivery, and what happens when something goes wrong. Getting this choice right at design time prevents an entire class of production incidents.
Before we go deep on architecture, let me give you the mental model I use when explaining this to everyone from junior developers to C-suite executives. It works every time.
You dial one specific person. You wait on hold until they pick up. You ask your question. They answer. You hang up. You know immediately if they answered or not. If the line is busy, you get an error. It is synchronous, direct, one-to-one, and blocking.
You broadcast on a frequency. Anyone tuned in to that station hears it, one listener or one hundred, you broadcast once. You do not wait for anyone to respond. You do not know or care who is listening. It is asynchronous, one-to-many, and non-blocking.
You register your address with a delivery company: “When you have something for me, ring my doorbell.” The company pushes to you when something happens. You never need to keep calling them to ask. It is push-based, event-triggered, and crosses system boundaries.
Nobody calls 1,000 people individually to tell them a radio show is starting. Nobody broadcasts on a radio station when they need a specific answer from one person. Nobody polls a delivery company every 5 minutes asking “do you have a parcel for me?” Each pattern exists because the others would be absurd in that context. The same logic applies to your architecture.
Salesforce exposes several API flavours including REST, SOAP, Bulk, Streaming, Composite, and more. They all share one fundamental characteristic: they are request-response patterns. The calling system asks a question and waits for an answer before proceeding. This blocking behaviour is both their strength and their limitation.
When the API Is the Right Tool
Use a Salesforce API when you need an immediate, confirmed answer. Retrieving a specific Account record to display in a third-party portal. Creating an Order in Salesforce when a customer checks out on your e-commerce platform and you need the Salesforce record ID back immediately to display a confirmation. Checking whether a Lead already exists before creating a new one. These are all phone-call scenarios where you need the other party to pick up and respond before you can move on.
Every synchronous API call from within Salesforce Apex (callouts in triggers, flows, or processes) counts against your synchronous callout limits: 100 callouts per transaction, 10 seconds per callout timeout, 120 seconds total. Call an ERP API synchronously on every Opportunity save and you will hit these walls under load. The fix is not increasing limits. The fix is switching to Platform Events.
API Types at a Glance
| API Type | Best For | Pattern | Watch Out For |
|---|---|---|---|
| REST API | CRUD on records, external app integration, mobile | HTTP GET/POST/PATCH/DELETE | API version management, error handling |
| SOAP API | Enterprise legacy system integration, complex data types | XML over HTTP | Verbose payloads, strict schema contracts |
| Bulk API 2.0 | Large data loads, millions of records | Async batched jobs | Not for real-time. Designed for batch. |
| Composite API | Multiple record operations in one call | Batched REST request | All-or-nothing transaction risk |
| Connect API | Chatter, Communities, Experience Cloud | REST | Separate limits from core REST API |
Sample: REST API Call from External System into Salesforce
// External system creates a Lead in Salesforce via REST API // POST /services/data/v59.0/sobjects/Lead/ const response = await fetch(`${instanceUrl}/services/data/v59.0/sobjects/Lead/`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ FirstName: 'Jane', LastName: 'Doe', Company: 'Acme Corp', Email: '[email protected]', LeadSource: 'Web' }) }); // Caller WAITS here. Execution is blocked until Salesforce responds. const result = await response.json(); console.log(`Lead created with ID: ${result.id}`); // ← need this ID immediatelyJavaScript · REST API
If the calling system needs a record ID, a status confirmation, or a data value back before it can proceed, use the API. If the calling system only needs to notify that something happened, and does not need a synchronous response, consider Platform Events or a Webhook instead.
Platform Events are Salesforce’s implementation of the publish-subscribe (pub-sub) pattern. A publisher fires an event onto the Salesforce Event Bus and immediately returns. It does not wait. It does not check if anyone is listening. It broadcasts the signal and moves on. Subscribers (Apex triggers, Flows, MuleSoft, external systems via CometD) independently consume those events at their own pace.
This architectural pattern eliminates the most common causes of Salesforce integration failure: synchronous coupling, governor limit breaches on triggers, and cascade failures when a downstream system is unavailable.
How Platform Events Work: Architecture View
Defining and Publishing a Platform Event
// Step 1: Define your Platform Event in Setup (or via Metadata API) // Object: Order_Placed__e // Fields: OrderId__c (Text), CustomerId__c (Text), Amount__c (Number), Status__c (Text) // Step 2: Publish from Apex (e.g. when Opportunity is Closed Won) trigger OpportunityTrigger on Opportunity (after update) { List<Order_Placed__e> events = new List<Order_Placed__e>(); for (Opportunity opp : Trigger.new) { if (opp.StageName == 'Closed Won' && Trigger.oldMap.get(opp.Id).StageName != 'Closed Won') { events.add(new Order_Placed__e( OrderId__c = opp.Id, CustomerId__c = opp.AccountId, Amount__c = opp.Amount, Status__c = 'New' )); } } // Publish: returns IMMEDIATELY. Trigger does not wait for subscribers. EventBus.publish(events); }Apex · Platform Event Publisher
// Step 3: Subscribe via Apex Trigger on the Platform Event trigger OrderPlacedSubscriber on Order_Placed__e (after insert) { for (Order_Placed__e event : Trigger.new) { // This runs asynchronously, fully decoupled from the publisher OrderService.createFulfilmentRecord( event.OrderId__c, event.CustomerId__c, event.Amount__c ); } }Apex · Platform Event Subscriber
Every Platform Event is stored on the Event Bus for 72 hours with a monotonically increasing ReplayId. If a subscriber goes down for 4 hours during a maintenance window, it can resume from the last processed ReplayId when it comes back up. No events are lost. No re-processing logic required. This is the feature that makes Platform Events safe for critical business processes. A direct API call can never guarantee this.
Platform Events vs. Change Data Capture (CDC)
A common point of confusion: Salesforce also offers Change Data Capture (CDC). These are automatic events fired whenever a standard or custom object record changes. The difference is intent. Platform Events are business events you deliberately define and publish: “An order was placed.” CDC events are data-layer change signals: “The Account record with ID 001XYZ was updated, here are the changed fields.” Use Platform Events for business process events. Use CDC when an external system needs to sync Salesforce data changes in near-real-time without polling the API.
Webhooks are not a Salesforce-native concept. They are an industry-standard pattern used by virtually every modern SaaS platform: Stripe, Shopify, GitHub, Twilio, Slack, HubSpot, and hundreds more. Understanding webhooks is essential for any Salesforce architect because Salesforce is almost never an island. It lives inside an ecosystem of external platforms that need to push data into it when things happen.
The webhook pattern is simple: an external system registers a URL with you: “when event X happens, POST the details to this URL.” When the event fires, the external system sends an HTTP POST to your endpoint. You process it. Done. No polling. No cron jobs. No “check every 5 minutes if anything changed.”
Real-World Webhook Scenarios Every Salesforce Team Deals With
Always return HTTP 200 immediately when you receive a webhook, before doing any processing. Webhook senders like Stripe expect a response within 5–30 seconds. If you try to synchronously process the payload and update Salesforce before responding, your endpoint will time out under load and the sender will retry, causing duplicate processing. Return 200 first, then hand off to an async queue or Platform Event for processing.
Webhook Security: Never Trust, Always Verify
// Webhook endpoint (Node.js / MuleSoft receives Stripe event) // STEP 1: Verify the signature BEFORE processing anything app.post('/webhook/stripe', express.raw({type: 'application/json'}), (req, res) => { const sig = req.headers['stripe-signature']; const secret = process.env.STRIPE_WEBHOOK_SECRET; let event; try { // Stripe signs every payload. Verify it came from Stripe, not an attacker. event = stripe.webhooks.constructEvent(req.body, sig, secret); } catch (err) { return res.status(400).send(`Webhook signature verification failed`); } // STEP 2: Return 200 IMMEDIATELY, before any processing res.status(200).json({ received: true }); // STEP 3: Async processing. Publish to queue or Platform Event. if (event.type === 'payment_intent.succeeded') { processPaymentAsync(event.data.object); // non-blocking } });Node.js · Webhook Receiver
Salesforce’s own Outbound Messages (part of Workflow Rules) are effectively Salesforce acting as a webhook sender, firing a SOAP-based HTTP POST to an external endpoint when a record condition is met. They are the legacy version of the pattern. For new implementations, use Platform Events to trigger a MuleSoft or middleware flow that POSTs to the external system, this gives you far more control, retry logic, and observability.
Here is the decision framework I walk every architect through when we are designing a new integration. Answer these questions in order:
Integration Pattern Decision Checklist
| Scenario | API | Platform Event | Webhook |
|---|---|---|---|
| External app creates a Lead and needs the new record ID back | ✓ Best choice | ✗ No response | ✗ Wrong direction |
| Opportunity Closed Won triggers ERP + billing + fulfilment + notifications | ⚠ Risky: blocking, N calls | ✓ Best choice | ✗ Wrong pattern |
| Stripe payment success → update Salesforce Opportunity stage | ✓ Works (via middleware) | ✓ After receiving | ✓ Stripe sends webhook |
| Salesforce Account update → sync to external data warehouse | ⚠ Polling required | ✓ CDC + subscriber | ✗ Salesforce is sender here |
| Load 500,000 records from data migration into Salesforce | ✓ Bulk API 2.0 | ✗ Not for bulk | ✗ Not appropriate |
| Real-time order status update displayed in Experience Cloud portal | ✓ REST API poll | ✓ Platform Event + LWC | ✓ If external pushes |
A mortgage lender approves a loan in Salesforce Financial Services Cloud. The approval needs to trigger: document generation, legal system notification, branch notification, customer SMS, and CRM update across 5 different systems.
Customer places an order on Shopify. Salesforce needs to create an Order record and the ERP needs to process fulfilment. Previously: polling Shopify API every 5 minutes. Missed orders during peak. Race conditions on duplicate processing.
Hospital EHR system discharges a patient. Salesforce Health Cloud needs to update case status, trigger a follow-up care flow, and notify the care coordinator. The EHR fires a webhook. Previous approach used a nightly batch file causing a 12-hour lag on critical care actions.
Industrial equipment sends telemetry to an IoT platform (AWS IoT). When a sensor threshold is breached, a field service work order needs to be created in Salesforce Field Service and the nearest technician dispatched automatically.
A SaaS company bills customers through Stripe. When payment is received, the Salesforce Opportunity must close, the contract activated, and a revenue recognition entry created, all in under 30 seconds for real-time dashboard accuracy.
An insurer receives a FNOL (First Notice of Loss) through a digital portal. It needs to create a claim record, check fraud scoring API, assign an adjuster, send customer confirmation, and update the policy system, previously a synchronous API chain that caused 12-second user wait times.
For Salesforce Architects and Developers
Run an integration audit. Pull up your current Salesforce org’s outbound API callouts and check your Apex classes and triggers for any synchronous HTTP callouts made from record-save contexts. Each one is a potential performance bomb and a future production incident waiting to happen. For every callout you find, ask: does the caller actually need the response synchronously? If not, that is a Platform Event candidate.
Second action: look at your external system integrations, especially your SaaS platforms like Stripe, Shopify, GitHub, or any payments/logistics provider. If any of them are being polled via scheduled jobs, check if they offer webhooks. They almost certainly do. Replace the polling job with a webhook receiver and eliminate an entire class of latency and missed-event issues.
Create your first Platform Event definition in a sandbox today. It takes 10 minutes. Define Order_Notification__e with three text fields. Write a 5-line Apex publisher. Write a trigger subscriber that logs to debug. Deploy and test it. Once you feel that decoupled, asynchronous publish-subscribe pattern working in practice, you will never want to use a synchronous API callout in a trigger again.
For Business and Technology Leaders
Ask your architecture team one question: “In our Salesforce integrations, are we using synchronous API calls in places where an asynchronous event-driven pattern would be more resilient and scalable?” If they cannot answer that clearly, schedule an integration architecture review. The pattern choices made at design time are invisible until they cause an incident, and then they become the most expensive decisions in the project.
| Timeframe | Architects / Developers | Business Leaders |
|---|---|---|
| This Week | Audit synchronous callouts in triggers. Identify Platform Event candidates. Build first Platform Event in sandbox. | Ask your team: where are we polling instead of subscribing? What integration failures occurred in the last 6 months? |
| 30 Days | Create internal decision framework for API vs. Platform Events vs. Webhooks. Document it for your team. | Request an integration architecture review as part of your next technology roadmap session. |
| 60 Days | Replace top 3 highest-risk synchronous callouts with Platform Events. Add replay monitoring. | Baseline your integration reliability metrics. Track failed callout rates before and after pattern changes. |
I have debugged integrations at 2am that were failing because a well-intentioned developer made an API call from a trigger that ran 200 times per second during a batch import. I have seen Platform Events replay 40,000 messages after a 3-hour subscriber outage, perfectly, with zero data loss. I have watched webhook implementations silently lose 3% of Stripe payments because someone forgot to return HTTP 200 before processing. These are not edge cases. They are patterns.
The mental models in this article (phone call, radio broadcast, doorbell) are the ones I use in every architecture review. They are simple enough for a business leader to understand and precise enough to drive the right technical decision. Use them.
Are you currently dealing with performance issues or data consistency problems in a Salesforce integration? Drop your scenario in the comments. I would genuinely like to help diagnose which pattern might be causing the issue.
