Pre-Black Friday: 20% off, for as long as you stayEARLYBFon Solo and AgencyEnds Nov 28Start free

How-to guide

How to Rank Enrichment APIs by Developer Experience (9 APIs, One Test Script)

Developer experience is measurable. Run the same five calls against each API, score what you see, and ignore the marketing page.

Get your free API key →Free to start. No credit card. 1,000 records to spend whenever you like.

TL;DR

  • Score every API on the same five calls: a free size check, a search, an enrichment, a miss, and a rate-limit burst. Developer experience shows up in those, not in feature lists.
  • The first API takes about 30 minutes and the rest about 10 each. On LeadOcean the whole run spends 4 records.
  • Our scorecard is below. We did not run these nine in production for you, so the table uses each vendor's own docs, with sources and the month checked.

Prerequisites

  • A LeadOcean API key from the free plan, exported as $LEADOCEAN_API_KEY. Free is 1,000 records for life, no card, 5 requests a second.
  • curl and jq.
  • A free or trial key for each competitor you want to score. Some have none (see the table).
  • A text file for the scorecard. Five columns are enough.

Step 1: Fix the five checks

Pick the checks before you open any docs. Otherwise the vendor with the nicest docs site wins.

  1. Free size check. Can you count an audience before you pay? Counts that cost nothing remove most budget surprises.
  2. Search call. Is the request body flat JSON, are filters arrays, how do you page?
  3. Enrichment call. What identifiers does it take, and what comes back?
  4. Miss behavior. Does a person with no data cost you a credit?
  5. Rate limit. What is the ceiling on the key you will actually use, and what does a 429 tell you?

Score each 0 to 2. Maximum is 10.

Step 2: Size the audience for free

LeadOcean has two free sizing paths: the leadocean_count_leads MCP tool and count=true on search with limit=1. Run the second from the shell.

bash
curl -s "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"title":["Head of Engineering","VP Engineering"],"country":["US"],"technologyCategories":["Payment processors"]}' \
  | jq '.meta'

count is a query parameter, not a body field. The body rejects unknown fields. meta.total is capped at 100,000, and the call spends no records.

Step 3: Pull three rows and enrich one

Search with a flat body, filters as arrays, and limit between 1 and 100. Three rows cost three records.

bash
curl -s https://api.leadocean.io/v1/people/search \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"title":["Head of Engineering"],"country":["US"],"limit":3}' \
  | jq '{n: (.data|length), next: .meta.nextCursor}'

Enrich takes exactly one of linkedin_url, email, phone or person_id. There is no name plus domain lookup, so search by domain first and enrich by person_id.

bash
curl -s https://api.leadocean.io/v1/people/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"person_id":"REPLACE_WITH_ID_FROM_SEARCH","reveal_email":true}'

Since October 2026 the enrich response also carries career history in resume_data: past roles, education, certifications and awards. Score that in check 3 if you need it.

Step 4: Force a miss and a burst

A miss is where billing models differ most. Send an identifier we hold nothing for.

bash
curl -s -o /dev/null -w "%{http_code}\n" \
  https://api.leadocean.io/v1/people/enrich \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"email":"nobody@acme.example"}'

A person we hold nothing for returns 404 and costs nothing. Then check your usage with GET /v1/usage, which is also free, to confirm the counter did not move.

Now the burst. On Free the limit is 5 requests a second, so send 8 in parallel and expect 429 with a Retry-After header.

bash
seq 8 | xargs -P 8 -I{} curl -s -o /dev/null -w "%{http_code}\n" \
  https://api.leadocean.io/v1/account -H "x-api-key: $LEADOCEAN_API_KEY"

Step 5: Fill the scorecard from the docs

Run steps 2 to 4 against each competitor with its own free key. Where there is none, read the docs and record what they state. This is what the nine looked like in September 2026.

APIFree allowanceEnrichment rate limitSource
LeadOcean1,000 records for life5 a second Free, 50 Solo, 200 Agencyfacts: leadocean.io/pricing
Apollo75 credits a month1,000 a minute on paid plansrate limits, pricing
People Data Labs100 credits a month, contact data obscured1,000 a minute on paid plansusage limits, pricing
FullEnrich50 trial credits60 calls a minutevolume docs, pricing
Hunter50 credits a month15 a second on enrichment endpointsAPI docs, pricing
Prospeo100 credits a month5 a second on Starterrate limits, pricing
CrustdataNo public price15 a minute on person enrichrate limits, pricing
Lusha40 credits a month50 a minute on ProAPI guide, pricing
LeadMagicNo free plan600 a minute on Email FinderEmail Finder, plans

All competitor figures were read in September 2026. Limits differ in unit (second against minute) and in scope (per key, per team, per endpoint), so convert before you compare.

How we read it

  • Highest ceiling on paper: Apollo and People Data Labs at 1,000 a minute on paid plans. That is about 17 a second.
  • Lowest ceiling: Crustdata at 15 a minute and FullEnrich at 60 a minute by default.
  • Miss billing: People Data Labs, FullEnrich, Hunter, Prospeo and LeadMagic state that a miss costs nothing for their main lookups. Check the exact endpoint before you rely on it.
  • Free allowance: LeadOcean's 1,000 records are one-off and larger than any monthly free allowance in the table. The tradeoff is that they do not renew.

Step 6: Score and decide

Give each API 0, 1 or 2 per check, then add up. Use the same rubric every time.

Check012
Free size checkNoneCounts cost creditsCounts are free
Search callNo filters, or a query-string DSLFilters but awkward pagingFlat JSON, arrays, cursor
Enrichment callOne input typeSeveral, with gapsDocumented inputs and a clear 404
Miss behaviorMisses are billedUnclear in the docsMisses are free
Rate limitUnder 1 a second, unexplainedDocumented, per-minuteDocumented, per-second, with Retry-After

Then weigh the score against your own volume. A 60-a-minute limit is fine for a nightly job of 5,000 rows. It is a wall for a signup form that enriches in real time.

Two cautions. First, a free key and a paid key can behave differently, so rerun the burst on the plan you will use. Second, do not score on data quality here. This test measures the API, not the match rate. Take a sample of 200 of your own contacts for that, and send the same list to every vendor.

Step 7: Log the result

Keep one row per API in a file so you can rerun it in a quarter. Docs change. Rate limits move, free plans appear and vanish, and a score from last year is a guess.

bash
printf "%s,%s,%s,%s\n" "$(date +%F)" "leadocean" "free-size=2,search=2,enrich=2,miss=2,rate=2" "notes" >> scorecard.csv

Fill the scores from what you saw, not from what the pricing page promises. If a vendor blocks your test or the docs contradict each other, write that down as an open item instead of guessing.

What you get

Here is the free count call from the LeadOcean MCP server, run on 2026-10-21. It spent 0 records.

json
{
  "query": {"title": ["Head of Engineering", "VP Engineering"], "country": ["US"], "technologyCategories": ["Payment processors"]},
  "total": 30,
  "totalIsExact": true,
  "totalAll": 53,
  "distinctCompanies": 19
}

total counts only mailable people (verified, catch_all_valid or catch_all). totalAll is the same filters with no email condition. The gap is the point: always say which one you quote.

A search row looks like this (response shape from the API reference, placeholder values):

json
{
  "success": true,
  "data": [{
    "profile_data": {"profile_full_name": "Jane Doe"},
    "contact_data": {
      "contact_current_experiences": [{"job_title": "Head of Engineering", "company_name": "Acme", "company_domain": "acme.com"}],
      "has_email": true,
      "email_status": "verified"
    },
    "meta": {"source_ids": {"person_id": "123456", "person_group_id": "123456"}}
  }],
  "meta": {"count": 3, "limit": 3, "nextCursor": "<opaque cursor>"}
}

Send meta.source_ids.person_id back to POST /v1/people/enrich in Step 3. Pass meta.nextCursor back unchanged to page.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyRe-export $LEADOCEAN_API_KEY and check there is no trailing newline
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Back off for the Retry-After value, or move up a plan
402The 1,000 free records are spentOpen app.leadocean.io and pick a plan, or narrow the sample
Empty dataEnum filter value is not an exact stringLook it up with leadocean_list_enum_values, for example jobLevel C-Team
Count looks stuck at 100,000meta.total is capped thereAdd filters until the total falls below the cap
Export refusedOver 50,000 rows a request or 500,000 a daySplit the request by country or seniority

FAQ

Is this a ranking?

No. It is a method plus a table of documented limits. Developer experience depends on your volume, language and budget, so rank the nine yourself with the scorecard.

Which API is best for a small team that writes code?

The one that lets you finish the five checks without a card. LeadOcean's free plan covers all five. Hunter, Apollo, Prospeo and People Data Labs have free plans too, with monthly allowances.

Why test misses?

Pipelines retry. If every miss costs a credit, a retry loop on a bad list burns budget fast.

Can I do this from an AI client instead of curl?

Yes. LeadOcean's hosted MCP server at https://api.leadocean.io/mcp has 13 tools. Sign in with OAuth, no key pasted. See data enrichment for developers.

Where do I read more?

Score LeadOcean on your own five calls

Free to start. No credit card. 1,000 records to spend whenever you like.

Get your free API key →