Most integration pain traces back to a pattern chosen by habit rather than fit. A team reaches for real-time callouts because the last project used them, then wonders why governor limits and timeouts appear under load. The right pattern falls out of two honest questions: how fresh does the data need to be, and how much of it moves?
Be honest about latency requirements
"Real-time" is the most over-requested requirement in integration work. Genuinely real-time needs, a credit check during checkout, an address validation as someone types, are worth the cost and complexity of synchronous calls. Most requirements are actually "within a few minutes" or "by tomorrow morning," and those are far cheaper and more resilient to serve with asynchronous or batch patterns.
Match the pattern to the shape of the data
For low-volume, high-urgency needs, a synchronous request-and-reply keeps things simple. For high-volume movement, nightly ERP syncs, bulk loads, batch processing respects limits and recovers cleanly from failure. For event-driven work where many systems care about the same change, publishing platform events lets consumers react without the source system knowing or caring who is listening. Fire-and-forget suits notifications where a lost message is tolerable; a durable queue suits anything where it is not.
Design for failure explicitly
Integrations fail in normal operation, not just in disasters. Decide up front what happens when a callout times out, when the remote system is down, and when a payload is malformed. Retries with backoff, idempotent operations so a repeated message is safe, and dead-letter handling for messages that can't be processed are not gold-plating; they are the difference between an integration that self-heals and one that pages someone at 2 a.m.
Mind the platform limits
Salesforce enforces limits on API calls, callout time, and payload size. A pattern that works in testing can collapse at production volume if it ignores them. Bulk API for large loads, sensible batch sizes, and awareness of concurrent-request limits keep an integration inside the guardrails. Designing for limits from the start is far easier than retrofitting once you've hit them.
Name an owner for the integration
An integration spans two systems and often two teams, which is exactly how it ends up owned by neither. Assign clear ownership for monitoring, for the data contract, and for responding
when something breaks. The most robust technical design still fails operationally if no one is watching it.
The takeaway
Let requirements pick the pattern: real freshness needs earn synchronous calls, volume favors batch, and shared events favor a publish-subscribe model. Then design for failure, respect the platform limits, and give the integration an owner. That sequence prevents most of the incidents that integration projects are remembered for.
