Integrations · Salesforce
We have no Salesforce app and no AppExchange listing. Nothing to install. You reach RichAPI from Salesforce through an Apex callout on a Named Credential, an HTTP Callout in Flow, or middleware sitting between the two, and you write the result to the object yourself.
Last updated September 22, 2026
Copy, paste, edit the brackets, run.
Why it matters
Every enrichment vendor with a managed package is also a vendor whose field mapping you will spend a week fighting. Doing it as a callout means you decide which object, which field, and what happens on a miss. A miss on our waterfall endpoints costs you nothing, so the nightly re-verify job is affordable to run.
We have no AppExchange listing, no managed package, and no Salesforce-native app. If you came here to click Install, stop reading and go look at a vendor who has one. That is a real reason to pick someone else and we would rather you find out in the first paragraph than after a sales call. What we have is an HTTP API that Salesforce can call three different ways. All three work. None of them involve a package upgrade breaking your sandbox.
Setup → Named Credentials. Create an **External Credential** using the Custom authentication protocol, with a named principal carrying a parameter for the API key. Then a **Named Credential** pointing at `https://api.richapi.ai`, referencing that external credential, with `x-api-key` set from the principal parameter. Then grant the principal on a permission set. Do this before you write anything, because the alternative is an API key in an Apex class in a repo, and that key is now in every sandbox refresh anyone has ever taken.
This is the path for anything bulk or asynchronous, which is most of it. ```apex public class RichApiEnrich implements Queueable, Database.AllowsCallouts { private List<Id> leadIds; public RichApiEnrich(List<Id> ids) { this.leadIds = ids; } public void execute(QueueableContext ctx) { List<Lead> toUpdate = new List<Lead>(); for (Lead l : [SELECT Id, Name, Website FROM Lead WHERE Id IN :leadIds]) { HttpRequest req = new HttpRequest(); req.setEndpoint('callout:RichAPI/api/v1/email_finder'); req.setMethod('POST'); req.setHeader('Content-Type', 'application/json'); req.setBody(JSON.serialize(new Map<String, Object>{ 'full_name' => l.Name, 'company_domain' => l.Website })); HttpResponse res = new Http().send(req); Map<String, Object> body = (Map<String, Object>) JSON.deserializeUntyped(res.getBody()); if (body.get('success') == true) { Map<String, Object> d = (Map<String, Object>) body.get('data'); toUpdate.add(new Lead(Id = l.Id, Email = (String) d.get('email'))); } } if (!toUpdate.isEmpty()) update toUpdate; } } ``` Two Salesforce constraints shape this and you cannot design around them: - **No callouts after DML in the same transaction.** Enrich, collect, then update once at the end. The loop above does that on purpose. - **Callouts per transaction are capped.** Chunk the list and chain Queueables, or use Batch Apex with a small scope size. A list view button that tries to enrich a thousand leads synchronously will fail, and it will fail in a way that looks like our API broke. Check `body.get('success')` and not the status code. A waterfall miss returns **200** with `"success": false` and `"billed": false`. If you branch on `res.getStatusCode() == 200` you will write blank emails onto good leads.
For one record at a time, on a button or a record-triggered Flow, the **HTTP Callout** action in Flow Builder works without a line of Apex. Point it at the Named Credential, give it a sample response so Flow can build the data structure, and branch on `success` in a Decision element. Flow can also generate the invocable action from an OpenAPI spec via External Services. Ours is live at `api.richapi.ai/api/v1/openapi.json`. The import is fussy about schema features and we have not certified it. Flow is the wrong tool for volume. One record, on demand, is what it is good at.
If you do not want Apex in your org at all, put [n8n](/integrations/n8n) or [Make](/integrations/make) in the middle. New Lead fires a webhook, the middleware calls us, and its Salesforce node writes the record back. You trade a deployment for a subscription and a second place where things can break.
| Endpoint | Cost | | --- | --- | | `email_finder` | `5 credits` | | `email_verifier` | `2 credits` | | `phone_finder` | `25 credits` | | `enrich_company` / `enrich_profile` | `1 credit` | | `find_linkedin_url_by_email` | `4 credits` | Full price only on results, scoped: `email_finder`, `email_verifier` and `phone_finder` cost zero when the providers all come back empty. The rest bill on a successful 2xx even if the payload is thin. Nothing non-2xx ever bills. Tiers on [/pricing](/pricing). That scoping is what makes a nightly hygiene job sane. Running `email_verifier` across a stale database costs you the hits and not the dead rows. Store `execution_log` on the record next to the enriched fields. Waterfall calls return one entry per provider attempt with a status, and a year later that is the only evidence of why a field is blank. Write it to a long text field on the record and your "why is this lead missing an email" question becomes answerable a month later.
No app, no field mapping, no sync, no sending, no prospecting UI, no SCIM. We return JSON. You own the object model, and honestly you should. Nobody's managed package has ever guessed your custom fields correctly. Related: [company enrichment API](/api/company-enrichment), [email verifier API](/api/email-verifier), [HubSpot](/integrations/hubspot) for the other CRM with the same answer, [verify before sequence push](/use-cases/verify-before-sequence-push), and the full [integrations index](/integrations).
**Is RichAPI on the AppExchange?** No. No listing, no package, no plans we can promise on a marketing page. **Can I install this in a sandbox and test it?** Yes. Named Credential plus the Apex above, on the 25 free credits. **Does it write to Salesforce itself?** No. We answer lookups. Every write is yours, which is also why there is no sync to break. **What about Salesforce's callout limits?** They are Salesforce platform limits, not ours. Asynchronous Apex with chunking is the standard answer; check the current numbers in Salesforce's own limits documentation. **Does `enrich_company` take a website?** No, a LinkedIn company URL. Resolve the domain first if that is all the Account has. **Can I give each business unit its own key?** Named keys with per-key usage attribution, yes. Not per-key credit budgets, because the pool is shared.
25 free credits, no card. Build the Named Credential and run one Queueable against ten leads before you commit to anything.