TL;DR
- Fetch the contact's email, call
POST /v1/people/enrichonce, andPUTjob title and company into ActiveCampaign custom fields. Eight runners can do it. - The first runner takes about 40 minutes. Each extra one takes about 10.
- It spends one LeadOcean record per contact we hold. A miss is a 404 and costs nothing, so the free 1,000 covers a real test.
ActiveCampaign's API reference describes contacts, custom fields and automations. It does not show a built-in step that fills a title or company from outside data. So "enrichment tool" here means a runner you wire up once, around one lookup and one write.
The eight runners are the same recipe in different clothes:
- A small script you host.
- An ActiveCampaign webhook that calls your script.
- Zapier.
- Make.
- n8n.
- Clay.
- A CSV from the LeadOcean Exports page.
- A nightly cron sweep.
Prerequisites
- An ActiveCampaign account with API access. Your API URL and key sit on the My Settings page, Developer tab (ActiveCampaign docs, September 2026).
- Two custom contact fields, for example
Job titleandCompany. Note their numeric field IDs. - A LeadOcean key from app.leadocean.io. Free has no card, 1,000 records for life and 5 requests a second.
- Secrets as shell variables, never in a page or repo.
export LEADOCEAN_API_KEY="paste-your-leadocean-key"
export AC_BASE="https://youraccountname.api-us1.com/api/3"
export AC_API_KEY="paste-your-activecampaign-key"ActiveCampaign authenticates with an Api-Token header and allows 5 requests per second per account (ActiveCampaign docs, September 2026). That is the real ceiling for every runner below.
Step 1: Size the job before you spend anything
A count costs nothing. This one ran on 2026-10-21 through the MCP tool leadocean_count_leads.
{
"jobFunction": ["Advertising & Marketing"],
"jobLevel": ["Director"],
"employeeRange": ["51-200"],
"country": ["US"],
"facets": false
}It returned 32,611 people with a verified, catch_all_valid or catch_all email, out of 102,507 with no email condition, across 18,848 employers. That is a mailable count, not everyone matching. Use it to judge a list you plan to add. For contacts already in ActiveCampaign, the cost is the number you enrich.
Step 2: Read the contact
List or fetch contacts from ActiveCampaign and keep the email and ID. Skip any contact whose Job title field is already filled, so you never overwrite what a rep typed.
curl -s "$AC_BASE/contacts/123" -H "Api-Token: $AC_API_KEY"The 123 is a placeholder contact ID.
Step 3: Enrich by email
Send exactly one identifier: linkedin_url, email, phone or person_id (LeadOcean docs, September 2026). On an email lookup, reveal_email defaults to true.
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"email":"jane.doe@acme.com"}'A 404 means we hold nothing for that person and costs nothing. Leave the contact alone.
Step 4: Write the fields back
ActiveCampaign updates a contact with PUT /contacts/{id}. Fields you leave out keep their values, and fieldValues saves custom fields in the same request (ActiveCampaign docs, September 2026).
curl -s -X PUT "$AC_BASE/contacts/123" \
-H "Api-Token: $AC_API_KEY" \
-H "content-type: application/json" \
-d '{"contact":{"fieldValues":[
{"field":"1","value":"VP Sales"},
{"field":"2","value":"Acme"}]}}'Field IDs 1 and 2 are placeholders for your own. Build the values from data.contact_data.contact_current_experiences[0].job_title and .company_name. Here is the whole loop:
import os, requests
LO = {"x-api-key": os.environ["LEADOCEAN_API_KEY"]}
AC = {"Api-Token": os.environ["AC_API_KEY"]}
BASE = os.environ["AC_BASE"]
def enrich(contact_id: int, email: str) -> None:
p = requests.post("https://api.leadocean.io/v1/people/enrich",
headers=LO, json={"email": email})
if p.status_code == 404:
return
p.raise_for_status()
job = (p.json()["data"]["contact_data"].get("contact_current_experiences") or [{}])[0]
if not job.get("job_title"):
return
requests.put(f"{BASE}/contacts/{contact_id}", headers=AC, json={"contact": {
"fieldValues": [
{"field": "1", "value": job["job_title"]},
{"field": "2", "value": job.get("company_name", "")}]}})Merge the two fields into a campaign with ActiveCampaign's personalization tags. Write "Hi, saw you lead marketing at Acme" only when both fields are filled.
Step 5: Pick a runner
All eight call the same two APIs. They differ in who hosts the trigger.
| # | Runner | Trigger | What you build |
|---|---|---|---|
| 1 | Your script | Webhook or schedule | enrich() above behind a small web server |
| 2 | ActiveCampaign webhook | A contact is added (subscribe event) | A webhook created through the API that posts to your script (ActiveCampaign docs, October 2026) |
| 3 | Zapier | ActiveCampaign trigger | Webhooks by Zapier to the enrich URL, then an ActiveCampaign update |
| 4 | Make | ActiveCampaign module | Two HTTP modules and a filter on status 404 |
| 5 | n8n | ActiveCampaign node | HTTP Request to LeadOcean, ActiveCampaign node to update |
| 6 | Clay | A table | An HTTP column, then a write to ActiveCampaign |
| 7 | CSV | Manual | Exports page CSV, then your own import |
| 8 | Cron | A schedule | The sweep below |
Zapier lists an ActiveCampaign app (Zapier, September 2026). Make documents an ActiveCampaign app that manages contacts and custom objects, and requires a paid ActiveCampaign account (Make, September 2026). n8n's node creates, gets, updates and deletes contacts, lists, tags and deals (n8n docs, September 2026). LeadOcean has no listing in any of them, so the enrich call is a plain HTTP request with an x-api-key header. See our Make recipe and Clay recipe.
For runner 7, the LeadOcean app has an Exports page with a filter builder, a column picker and the record price before you start. Bulk CSV export is not on Free. Request numbered columns such as email_1_address and phone_1_number.
For runner 8, stay under 5 requests a second on both sides:
0 6 * * * /usr/bin/python3 /opt/enrich/sweep.py >> /var/log/enrich.log 2>&1What you get
The response shape from the API reference, with placeholder values (not a real person).
{
"data": {
"profile_data": { "profile_full_name": "Jane Doe" },
"contact_data": {
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
],
"contact_emails": [
{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }
],
"contact_phones": [
{ "phone": "+1 415 555 0133", "type": "mobile" }
]
}
}
}Since 17 October 2026 the response can also carry career history in resume_data: past roles, education and certifications, each when held. After the run, the contact shows VP Sales and Acme in the two custom fields.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 from LeadOcean | Missing or wrong x-api-key | Re-copy the key and check the header name |
| 403 from ActiveCampaign | The user lacks the edit contacts permission | Use a key from a user who can edit contacts |
| 404 from enrich | We hold nothing for that identifier | Skip the contact. It cost nothing |
| 429 | Above the plan's rate limit (5 a second on Free, 200 on Agency) | Honor Retry-After and queue the calls |
| 402 | Free records are spent | Move to Solo at $97 a month or Agency at $497 a month |
| 422 from ActiveCampaign | Validation failed on the update | Check the field IDs and the values in the body |
FAQ
Does ActiveCampaign enrich contacts by itself?
Its API reference lists contact, custom field and automation endpoints. It shows no outside-data enrichment step (ActiveCampaign docs, September 2026). Check your plan in the app before you assume one exists.
Which runner should I pick?
Pick Zapier or Make if nobody writes code. Pick your script or n8n for full control of retries. Pick cron for a nightly sweep.
What does it cost?
Free gives 1,000 records once, with no card. Solo is $97 a month and Agency is $497 a month, with a fair-use pace instead of credits. See pricing and what enrichment is.
Will it overwrite what my reps typed?
Not with the guard in Step 2. Extend the same check to any field you want to protect.
Are there other CRMs I can do this for?
Yes. The shape is identical. See 5 enrichment tools for a less annoying CRM.
Fill your ActiveCampaign fields with real job titles
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →