Back to Blog
Salesforce Core

5 Things I Learned Building a Lead Enrichment Pipeline on Salesforce (With Agentforce & Apollo.io)

Richard Tuharsky
March 23, 2026
10 min read

I recently built an end-to-end lead enrichment automation on Salesforce, from trigger to AI-generated outreach recommendation, with zero human intervention. The pipeline calls Apollo.io for firmographic data, scores leads against ICP criteria, and uses Agentforce to post personalised outreach suggestions directly to Chatter.

It took about 5 hours to build, but the lessons behind it came from years of working inside the Salesforce ecosystem. Here is what I would pass on to anyone attempting something similar.

1. Design Your Data Model Before You Write a Single Line of Apex

This sounds obvious, but it is the step most people rush through. Before I touched any code, I created seven custom fields on the Lead object and a dedicated custom object for logging (Lead_Enrichment_Log__c).

Why? Because every downstream component, the parser, the scoring service, the Agentforce action, depends on those fields existing and being correctly typed. If I had started coding first, I would have been refactoring field types mid-build, which is a waste of time and a source of bugs.

The log object is especially worth calling out. I designed it as a black-box recorder: one record per enrichment attempt, storing the HTTP status code, response body, error message, and retry count. Without it, diagnosing bulk failures means clicking into every Lead record individually. With it, a single list view filtered to Status != Success gives you instant visibility into anything that went wrong.

Takeaway

Treat your data model as the foundation, not an afterthought. Future-you will thank present-you when debugging at scale.

2. One Lead Per Queueable Job Is Not Lazy, It Is Disciplined

My first instinct was to batch multiple leads into a single Queueable execution. It feels more efficient. But Salesforce governor limits do not reward ambition; they punish it.

Each chained Queueable job gets a completely fresh set of governor limits: 100 SOQL queries, 150 DML statements, 10 callouts. By processing one lead per job and chaining the rest, I guarantee that each lead gets its own clean transaction. If one lead's API call fails, it does not take down the rest of the batch.

This pattern also makes retry logic straightforward. A 429 (rate limited) response? Re-enqueue that single lead ID. No need to figure out which leads in a batch succeeded and which did not.

Takeaway

In async Salesforce work, simplicity per transaction beats cleverness per batch. Chain jobs instead of cramming them.

3. Defensive Parsing Is Not Optional With Third-Party APIs

Apollo.io does not guarantee every field in its response. A lead with only an email might return a person object but no organisation. The organisation might exist but have null revenue. I added null checks on every single field mapping in my parser, not because I enjoy boilerplate, but because one unexpected null from Apollo would crash the entire enrichment flow.

I also used typed inner classes for JSON deserialisation instead of the more common Map<String, Object> approach. Typed classes give you compile-time safety: if Apollo changes their response structure, the deserialisation fails predictably rather than silently returning null values deep in a nested map.

Takeaway

When integrating with external APIs, assume every field can be absent. Use typed deserialisation where possible. Your future debugging sessions will be much shorter.

4. Hard Disqualifiers Should Short-Circuit Your Scoring Logic

My ICP scoring system runs on a 0-100 point scale. Industry match? +20. Senior title? +20. Revenue above $10M? +20. But here is the thing: a student intern at Google with a business email could theoretically score 65+ on positive signals alone. That is a garbage lead dressed up in good data.

So I added hard disqualifiers at the top of the scoring method. If the title contains "intern," "student," or "trainee," the method returns 0 immediately. No amount of positive signals can override a fundamental disqualifier.

This matters more than you would think. Scoring systems that only add points create false confidence. The best scoring systems also know when to say "this lead is definitively not worth pursuing."

Takeaway

Every scoring model needs negative signals and hard stops, not just positive weights. Build your disqualifiers first, then your point system.

5. Agentforce Works Best When You Feed It Structured Context, Not Raw JSON

When I configured the Agentforce agent, I had a choice: pass it the raw JSON from Apollo, or build a structured context string with clear labels. I went with the structured approach:

Lead: Jane Doe | Title: VP Sales | Company: Acme Corp | ICP Score: 85 | Tier: Immediate Action

LLMs perform better when the input is human-readable and explicitly labelled. Raw JSON with nested keys and inconsistent nulls forces the model to parse structure before it can reason about content. A clean labelled string lets it go straight to reasoning.

The result is a Chatter post that actually reads like a useful recommendation, not a JSON dump with a prompt stapled to it.

Takeaway

If you are feeding data into an AI layer, invest the extra 10 minutes to structure and label it cleanly. The output quality improvement is disproportionate to the effort.

Final Thought

This project was not complex in the traditional sense, no custom Lightning components, no batch processing across millions of records. But it touched almost every layer of the Salesforce platform: triggers, async processing, HTTP callouts, custom objects, Named Credentials, and Agentforce. That is what makes it a strong portfolio piece: it demonstrates architectural thinking across the full stack, not just knowledge of one feature.

If you are building portfolio projects as a Salesforce consultant, pick something that crosses boundaries. The most impressive projects are not the ones with the most code, they are the ones where every component has a clear reason to exist.

Full Technical Case Study

Read the complete build with Apex source code

Architecture diagrams, all 6 Apex classes with syntax highlighting, Agentforce config, and the full scoring matrix.

View Case Study