Salesforce ships four distinct ways to push events out of the platform. They look similar on a slide deck and behave very differently in production. Picking the wrong one is the kind of decision you only catch six months in, when the volume is high enough to expose the contract you didn't read carefully.
Part 1 of this series covered the operational sharp edges of Platform Events specifically. This part steps back: how do you decide between CDC, Platform Events, the Pub/Sub API (what Streaming API has become), and Outbound Messaging in the first place?
The short answer: there's no universal best. Each mechanism guarantees a different thing. Match the guarantee to the requirement.
The Four Mechanisms and What They Actually Guarantee
Before the decision matrix, the contracts. Read these carefully — most bad architectural decisions in this space come from skipping this step.
Change Data Capture (CDC)
What it is: Salesforce publishes an event automatically whenever a record in an enabled object changes. Zero publisher code. The event payload includes the changed fields, the change type (CREATE/UPDATE/DELETE/UNDELETE), and a ChangeEventHeader with metadata (recordIds, changeOrigin, transactionKey, sequenceNumber).
What it guarantees:
- Only committed changes are published — a rolled-back transaction produces no event
- Events for the same record arrive in transaction order, scoped by
transactionKey+sequenceNumber - 72-hour retention on the event bus with
ReplayIdsemantics identical to Platform Events - Field-level visibility — you can see exactly which fields changed and their new values
What it does not guarantee:
- Global ordering across different records. Two updates to two different Accounts have no defined order relative to each other.
- Delivery within a specific time window. CDC is async — typical latency is seconds, but there's no SLA.
- Coverage of every field type. Long text areas, encrypted fields, and some standard fields are excluded from the payload.
Daily delivery allocation: based on edition. Enterprise Edition starts at 250,000 events/day shared across CDC and Platform Events combined; you can buy more via add-on SKU.
Platform Events
What it is: A custom-defined event channel. You design the schema (custom event object ending in __e), publish from Apex / Flow / Pub/Sub API, subscribe from triggers / Flows / external clients.
What it guarantees:
- Pub/sub fan-out — multiple subscribers receive the same event independently
- 72-hour retention with
ReplayId - Two publish behaviors: Publish After Commit (event fires only if the surrounding transaction commits) and Publish Immediate (fires regardless of transaction outcome — useful for error logging, dangerous for state-change signals)
What it does not guarantee:
- Ordering, even within a single channel. Part 1 covered this in detail.
- That the event will be delivered — high-volume floods can cause silent queuing past the hourly delivery cap (250k/hour default).
- Transactional consistency unless you use Publish After Commit.
Pub/Sub API (formerly Streaming API)
What it is: A gRPC-based bidirectional streaming API for publishing and subscribing to Platform Events and CDC events from external systems. It replaces the legacy CometD-based Streaming API and the deprecated PushTopic mechanism.
Status as of the Spring '26 release: the Pub/Sub API is the only supported path for new external subscribers. CometD remains available but is in maintenance — no new features, deprecation timeline being actively discussed.
What it guarantees:
- Efficient binary protocol (Avro-encoded payloads, HTTP/2 multiplexing) — significantly lower overhead than the legacy CometD HTTP long-polling
- Flow control — subscribers request a specific number of events via
FetchRequest, server doesn't push past that - Replay from a specific
ReplayIdorLATEST/EARLIEST - Same 72-hour retention as the underlying event bus
What it does not guarantee:
- It's not a separate event mechanism — it's an access protocol for the same Platform Events and CDC events. The ordering and delivery characteristics of those underlying events still apply.
This is important and routinely confused: "should we use Pub/Sub API or Platform Events?" is a malformed question. You publish a Platform Event; an external system consumes it via Pub/Sub API. They're stacked, not alternatives.
Outbound Messaging
What it is: A workflow / Flow action that POSTs a SOAP envelope to an external HTTPS endpoint when a record changes.
What it guarantees:
- Built-in retry with exponential backoff — Salesforce keeps retrying for 24 hours until the endpoint returns a SOAP acknowledgment
- Guaranteed delivery within those 24 hours if the endpoint comes back online
- Ordering preserved per workflow rule (sequential delivery)
- Zero subscriber code on the Salesforce side
- Configurable from Setup / Flow without writing Apex
What it does not guarantee:
- A modern data format. The payload is SOAP/XML. There's no support for JSON, gRPC, or any binary format.
- Anything beyond simple point-to-point. There's no pub/sub — each endpoint is configured individually.
- Compatibility with modern API gateways. SOAP endpoints with the strict envelope format Salesforce expects are increasingly rare to deploy.
This is the oldest mechanism in the list. It's also the most operationally reliable for the narrow use case it covers.
The Decision Matrix
The rows below are the requirements that actually determine the right choice; the columns are the four mechanisms. Find the rows that are hard requirements for your case, then pick the column that answers "Yes" to all of them — the mechanism whose column clears your must-haves is the one to ship.
| Requirement | CDC | Platform Events | Pub/Sub API | Outbound Messaging |
|---|---|---|---|---|
| Strict ordering required (per record) | Yes (per record, by transaction) | No | Inherits underlying event | Yes (per rule, sequential) |
| Volume > 50k events/hour sustained | Yes (with quota purchase) | Yes (with quota) | Yes (designed for this) | No (sequential delivery bottleneck) |
| External subscriber | Yes (via Pub/Sub API) | Yes (via Pub/Sub API) | Yes (this is the protocol) | Yes (it's the only option) |
| Field-level change tracking | Yes (changedFields header) | No (you define schema) | Inherits underlying event | Only fields you map into the message |
| Zero publisher code | Yes (auto-published on commit) | No (Apex/Flow publishes) | No (you publish via gRPC) | Yes (Workflow/Flow action) |
| Transactional consistency with commit | Yes (always post-commit) | Opt-in (Publish After Commit) | Inherits underlying event | Yes (post-commit) |
| Multiple independent consumers | Yes (subscribe per channel) | Yes (native fan-out) | Yes | No (one endpoint per config) |
| Custom payload schema | No (Salesforce defines) | Yes (you define __e fields) | Inherits | Limited (mapped fields only) |
A few notes on how to read this:
- "Yes" doesn't mean "good fit" — it means "the mechanism supports it." A row with multiple "Yes" answers still requires checking the rest of the contract.
- Pub/Sub API rows mostly say "inherits" because it's a transport, not an event source. Use the Platform Events or CDC row depending on what you're publishing.
- The "zero publisher code" row is where CDC and Outbound Messaging shine. If the requirement is "react to record changes without writing publisher Apex," those two are the only options.
Failure Modes When You Pick Wrong
Each mechanism has a characteristic way it fails when misapplied. Recognizing these post-mortems saves you from repeating them.
Platform Events used where CDC was the right answer
The symptom: you wrote an Apex trigger on every standard object the integration cares about, each trigger publishes a Platform Event with the changed record. Six months in, the trigger code is 1,500 lines, every new field added to those objects requires a trigger update, and the integration team complains that some changes are missed (because someone bypassed the trigger via Data Loader with the bypass field set).
The fix: use CDC. The publisher code disappears. The ChangeEventHeader already includes the changed fields. Bulk loads can't bypass it because the platform publishes the events, not Apex.
When the trap catches you: you started with one object and Platform Events seemed simpler. Then the requirement expanded to ten objects.
CDC used where Platform Events was the right answer
The symptom: you turned on CDC for Order__c because you wanted to fire a downstream workflow when orders complete. Now your subscriber receives an event for every field change on every order — including 50 status updates per order over its lifetime, plus changes from internal sales operations that have nothing to do with the downstream workflow. The subscriber filters most events out and you've burned through 80% of your daily CDC quota by 10 AM.
The fix: use Platform Events with a custom Order_Completed__e schema. The publisher fires exactly one event per completion. Quota usage drops by 50x. The downstream workflow doesn't need filtering logic.
When the trap catches you: CDC was the default because it required no publisher code. The actual requirement was a semantic event ("this order finished"), not a technical event ("this record changed").
Outbound Messaging used where Platform Events was the right answer
The symptom: you set up Outbound Messaging to a microservice's SOAP endpoint. Then a second microservice needs the same event. You add a second Outbound Message rule. Then a third. Now five rules fire on the same record change, the endpoint URLs are managed in Setup outside of source control, and rotating the auth on one endpoint took two hours of clicking through configuration screens.
The fix: publish a Platform Event once. Each microservice subscribes via Pub/Sub API. Endpoint configuration lives in each microservice. The event source has one rule.
When the trap catches you: there was originally only one consumer, and Outbound Messaging was the path of least resistance because no Apex.
Pub/Sub API treated as a separate event mechanism
The symptom: an architect spec'd "we'll use Pub/Sub API for the integration" without specifying whether it's consuming Platform Events or CDC. The dev team picks Platform Events because that's what the publishing team already used. Six months later, the requirement to track field-level changes can't be met — because Platform Events don't expose changed fields and the publisher would have to re-implement diffing logic.
The fix: name the underlying event type explicitly in the architecture decision. Pub/Sub API is how the external system talks to the bus; CDC vs Platform Events is what's on the bus.
When the trap catches you: any conversation that says "Pub/Sub API" without immediately following it with "for CDC events" or "for Platform Events."
Outbound Messaging on the critical path of a synchronous user flow
The symptom: a user clicks "Submit" in Salesforce, Outbound Messaging fires to an external API, and the user expects the response within seconds. Sometimes it works. Sometimes the external API is slow, Outbound Messaging waits up to its timeout, retries, and the user has long since refreshed and tried again — creating duplicate downstream state.
The fix: Outbound Messaging is async-only by design. If you need synchronous response on user action, use an Apex callout from a controller or a Flow Action with an HTTP-callout. Use Outbound Messaging only when fire-and-forget with 24-hour eventual delivery is acceptable.
When the trap catches you: the original requirement was async-OK, but a later UX requirement made the flow synchronous and nobody re-evaluated the integration mechanism.
Three Concrete Scenarios
The decision matrix is abstract. Three real situations to make it tangible.
Scenario 1: Sync committed Opportunity changes to a data warehouse
Requirement: every committed change to an Opportunity (insert/update/delete, all fields) must arrive in Snowflake within 5 minutes. The warehouse team owns the consumer. No business logic on the Salesforce side.
Pick: CDC + Pub/Sub API. The warehouse team's Snowflake-side ingestion service subscribes via Pub/Sub API and reads OpportunityChangeEvent. Zero publisher code on the Salesforce side. The changedFields header lets the warehouse team do delta merges efficiently. Replay buffer covers any consumer downtime up to 72 hours.
Why not Platform Events: the team would have to write a trigger on Opportunity to publish, hand-roll the changed-fields logic, and maintain it as the schema evolves. No upside.
Why not Outbound Messaging: SOAP/XML format is a non-starter for a modern data pipeline. Also, single-endpoint configuration doesn't scale if the team later adds a second consumer.
Scenario 2: Notify three internal microservices when an order completes
Requirement: when an Order__c reaches status "Completed", three internal services need to act — fraud check (synchronous-ish, latency-sensitive), inventory reservation (medium SLA), ERP sync (long-running). Salesforce shouldn't know about any of them by name.
Pick: Platform Event (Order_Completed__e) published from an Apex trigger that fires when status transitions to Completed. Three independent subscribers via Pub/Sub API, each with its own backpressure and replay semantics. Apex Publish After Commit ensures the event fires only on successful commit.
Why not CDC: the requirement is a semantic event ("completed"), not a record-changed event. CDC would fire on every status update and every other field change, requiring downstream filtering and burning quota.
Why not Outbound Messaging: three endpoints means three Outbound Message rules with three separate configs. Cross-team coordination becomes painful.
Scenario 3: Push an approval result to a legacy on-prem SOAP system
Requirement: a custom approval Flow completes and the result must be POSTed to a legacy procurement system. The procurement system only speaks SOAP and is behind a corporate firewall. Reliability matters more than latency — same-day delivery is fine.
Pick: Outbound Messaging. Zero subscriber code on either side. SOAP envelope is what the legacy system expects. Built-in 24-hour retry handles transient firewall outages without custom code. The fact that it's old technology matches the system it's talking to.
Why not Platform Events: an external SOAP consumer of a Platform Event would require building a bridge (Pub/Sub API client → SOAP transformer → procurement system). That's hundreds of lines of code and an additional service to operate, replacing something that does the job in three clicks.
Why not CDC: the trigger event is "approval result," not "record changed."
Decision Heuristics
A short checklist for the next time you face this choice:
- Is the event semantic (something happened) or technical (a record changed)? Semantic → Platform Events. Technical → CDC.
- Do you control the consumer? If it's external SOAP-only and reliability > latency → Outbound Messaging. Otherwise → Platform Events or CDC over Pub/Sub API.
- Does field-level diff matter? Yes → CDC (you get it free). No → Platform Events (smaller payload, custom schema).
- Is ordering critical per record? CDC orders by transaction per record. Platform Events do not order at all. Outbound Messaging orders per rule.
- Will volume exceed 50k events/hour sustained? Plan for the daily allocation and Pub/Sub API. Outbound Messaging is out at this point.
The single most common mistake: defaulting to Platform Events because it's the most flexible. Flexibility cuts both ways — it means you're now responsible for the publisher logic, the event schema, the ordering strategy, and the replay handling. CDC gives you most of that for free if the use case fits. Use the simpler mechanism when its contract matches.
This closes the Event-Driven Salesforce series. Part 1 covered the operational sharp edges of Platform Events; this part gave you the framework for choosing between all four mechanisms.
Questions or war stories? Find me on LinkedIn.