Integration Architecture
Publishing a Platform Event does not complete the integration
Accepted is not completed
A Salesforce team publishes a Platform Event, receives a successful result and closes the integration story. That is the point where the difficult work actually begins. A successful publish confirms that the event was accepted for publication. It does not confirm that every subscriber received it, that a downstream application processed it, or that the intended business outcome occurred.
Salesforce classifies this as a fire-and-forget pattern: the publisher and subscriber are decoupled, and the publisher does not wait for downstream completion. That separation is valuable because it reduces synchronous dependency and supports independent consumers. It also removes immediate certainty. If an order, payment or customer notification matters, the architecture needs a second mechanism for knowing what happened after dispatch.
Choose transaction semantics deliberately
Platform Events can be configured to publish immediately or after the originating transaction commits. The distinction is not cosmetic. With immediate publication, a subscriber can receive an event even if the database transaction that produced it later rolls back. If the consumer then queries Salesforce for the changed record, the state described by the event may not exist.
Use Publish After Commit when the event represents committed business state or the subscriber must read the resulting Salesforce data. Immediate publication still has valid uses, including telemetry about an operation that may fail, but the contract must say so. A name such as OrderConfirmed should never be emitted from a transaction that has not yet confirmed the order. Event timing is part of business meaning.
Design a business contract, not a record dump
A useful event explains what happened and gives consumers enough stable context to respond. Define an event type, source, occurred-at time, business identifier, correlation identifier, schema version and the minimum payload required by the chosen pattern. Avoid copying every field from the source record into the message. Large snapshots create unnecessary exposure and make consumers depend on fields they do not own.
Decide whether the event carries state or merely signals that the consumer should retrieve state. A notification-style event is smaller and keeps Salesforce authoritative, but it introduces a follow-up API dependency and the record may change before it is read. A state-transfer event gives the consumer a point-in-time fact, but increases payload governance and versioning work. Make that trade-off explicit for each event family.
Replay is a recovery window, not an archive
Salesforce retains Platform Events and Change Data Capture events on the event bus for 72 hours. Pub/Sub API clients can store a Replay ID and resume after a disconnection while the required events remain inside that window. The Replay ID is an opaque position in the stream; Salesforce warns that values are not necessarily contiguous and should not be calculated by the client.
The window gives a subscriber time to recover, but it does not replace a durable operational store. Commit progress only after the event has been safely processed or placed on a durable local queue. Monitor consumer lag against the retention window. If a subscriber can be unavailable for more than 72 hours, provide another recovery path, such as a source-system extract, reconciliation API or persisted outbox that can regenerate missing work.
Idempotency is the receiver's safety mechanism
A robust subscriber assumes that the same logical work can be presented more than once. Salesforce's Pub/Sub API guidance tells clients to handle duplicate events and identifies the system-generated event ID as the deduplication value for received Platform Events. Do not use Replay ID as the business identity of a message; Salesforce documents it as a stream position and notes that it is not guaranteed to remain unique through every maintenance scenario.
Store the event ID or a deliberate business idempotency key with the processing result. If the same key arrives again, return the previous outcome or safely skip the side effect. For operations such as creating invoices or taking payments, deduplication must sit beside the target transaction, not in a short-lived in-memory cache. A retry should repair interrupted work, never multiply it.
Make downstream failure visible in Salesforce
Fire-and-forget must not become fail-and-forget. Define states such as Dispatched, Received, Processing, Completed, Retryable Failure and Terminal Failure for business-critical operations. The downstream system or middleware should return a callback, publish a result event or update a durable integration-status record. That feedback loop lets Salesforce distinguish a message that left the org from an outcome that actually completed.
Separate technical retries from business rejections. A timeout or temporary service outage may be retried automatically with controlled backoff. An invalid customer identifier or rejected credit decision normally needs remediation, not another identical attempt. Preserve the original correlation key, attempt count, last error, next action and accountable owner so support teams can act without reconstructing the incident from raw logs.
Operate the flow end to end
Observability should follow the transaction across Salesforce, the event bus, middleware and the destination. Use one correlation identifier in each system and record enough timestamps to measure dispatch latency, consumer lag and processing duration. Monitor oldest unprocessed work, repeated retries, terminal failures and approaching replay-window exhaustion. A dashboard of publish counts alone measures activity, not reliability.
Add reconciliation for the business facts that cannot be lost. Compare orders confirmed in Salesforce with orders accepted by the ERP, or communications requested with provider outcomes. Reconciliation catches failures outside the happy path: expired replay positions, configuration mistakes, schema incompatibility and human changes made directly in a target system. The control may run hourly or daily; its importance depends on the consequence of divergence.
Test interruptions, not only throughput
A useful event test publishes realistic batches, disconnects the subscriber, resumes from stored progress and introduces duplicate deliveries. It verifies rollback behaviour for immediate and after-commit publication, checks schema compatibility across versions and confirms that a poison message cannot block unrelated work indefinitely. High volume matters, but reliability defects often appear during recovery rather than steady-state processing.
Include the people who will operate the integration. Give them a trace from a Salesforce record to its event, downstream transaction and final status. Prove that they can replay or resubmit safely, distinguish a delayed message from a rejected one and reconcile the affected population. If recovery requires a developer to query several systems and edit data manually, the integration is not production-ready.
The JSBC Labs view
Platform Events are excellent for decoupling systems, but decoupling transfers responsibility; it does not remove it. Define commit timing, keep the event contract purposeful, persist subscriber progress, make receivers idempotent, return downstream outcomes and reconcile important business state. Each of those decisions belongs in the architecture before the first publisher is built.
The right completion criterion is not that EventBus.publish returned successfully. It is that the organisation can prove what happened, recover within the available window and prevent a retry from causing harm. That is the difference between an event being emitted and an integration being reliable.