Most Salesforce enrichment integrations work around the platform. They run external schedulers, stand up background sync services, or push data through middleware that lives outside your org.
We went the other direction. The Enrich Layer integration runs its orchestration entirely inside Salesforce: no exports, no separate sync service, no middleware. Enrichment still calls the Enrich Layer API, but the workflow itself stays within the platform's own execution model. Here’s how we did it.
Working within Salesforce's world
Salesforce has specific ideas about how code should run. Execution contexts are short-lived and stateless. Each time your code runs, it starts fresh with no memory of what happened before. You can't maintain state implicitly across runs, and you can't run anything for more than a few seconds at a time.
For single-record enrichment, these constraints don't matter much. You click a button, we call the Enrich Layer API, we write the data back to your Salesforce fields, and you're done. The whole thing happens in a couple of seconds.
But bulk enrichment is different. When someone wants to enrich 5,000 contacts at once, you need a different approach.
The problem with bulk enrichment
We couldn't just loop through 5,000 records and call the API for each one. Salesforce would cease the execution before we got through the first hundred. And even if we could, we'd slam into the Enrich Layer API rate limits immediately.
Instead, we designed around chained Queueable jobs. Each job picks records off the queue, checks an in-org rate limiter before every API call, and when the API rate-limits us, schedules the next job using the Retry-After delay. The chain is bounded, at most 60 links deep. Batch size comes from the per-day rate limit you set in package settings during install, not from anything we read off the API.
This design works within Salesforce's execution time limits and stays under API rate limits. It’s not elegant, but it’s predictable.
