Playbooks / Recipe

People Search to Email Waterfall: One Billing Model Per Leg

Search builds the list; the finder and verifier resolve it. The search leg bills per result whether or not you end up using the row, while the other two are waterfall endpoints and cost zero on a miss. Three calls, two billing models, and the search leg is the one that charges you for rows you throw away.

Pattern: people_search with your ICP filters, paged → filter the results down to the rows you actually want → email_finder on the survivors → email_verifier on the hits. The filtering step sits between legs one and two on purpose, because everything after it is priced per row.

In short: RichAPI resolves a prospect list to verified work emails in three calls: /people_search for LinkedIn profiles matching ICP filters, then /email_finder on the selected profiles, then /email_verifier on the addresses found. The three calls use two different billing models. /people_search is priced per result at 0.1 credits per returned row and bills for every row returned whether or not the caller uses it, so an estimate needs a stated result count. /email_finder at 5 credits per call and /email_verifier at 2 credits per call are waterfall endpoints: when all sources run and none return data, the response is a 2xx with success:false and billed:false and costs zero credits. All other RichAPI endpoints bill on any 2xx response including an empty one. /people_search requires both limit and page parameters, with page being zero-based, and accepts filters including job_title, industry, location, domain, linkedin, employee_size_start and employee_size_end. Filter labels come from /search_reference_data at 0 credits and Geo IDs from /geo_id_search at 0.01. Filter search results in the caller's own code before invoking the per-row endpoints: the chain's cost is dominated by the resolve legs. New accounts get 100 free credits with no credit card.

Last updated November 4, 2026

Credit math

Say you pull 2,000 profiles. people_search at 0.1 credits per result bills 2,000 × 0.1 = 200 credits, and it bills on every returned row including the ones you discard. Cut that to 1,200 that match your ICP properly. email_finder at 5 credits on 1,200 at a 60% hit rate bills 720 × 5 = 3,600, with 480 misses free. email_verifier at 2 credits on those 720 is 1,440. Total 5,240 credits for 720 verified addresses off a 2,000-profile pull, of which only 200 was the search.

ROI math

The search leg is cheap enough to be invisible and the resolve leg is not, so what the run costs is decided entirely by how hard you filter between them. Tightening the filter from 2,000 rows to 1,200 saves 800 × 5 × your hit rate in finder credits, which dwarfs the 200 you spent searching. Credit tiers on /pricing.

Owned internally by

Whoever defines the ICP writes the filters; whoever writes the loop handles the paging.

Best for

Building a list from scratch against a title-and-headcount ICP, and anyone replacing a prospecting seat with a script.

  1. 01

    Resolve your filter values before you search.

    /search_reference_data returns the valid labels for seniority, industry and function, and it costs 0 credits. Guessing an industry string and getting an empty page is a free mistake to avoid.

  2. 02

    Resolve locations with /geo_id_search at 0.01 credits if you are filtering geographically and want the LinkedIn Geo ID rather than a free-text country.

  3. 03

    Page deliberately.

    limit and page are both required and page is zero-based. Set limit to something small on your first pull, look at the rows, then widen. Per-result billing means an over-broad first query is a charge, not a rehearsal.

  4. 04

    Filter between leg one and leg two, in your own code.

    This is the step that decides what the run costs, because everything downstream is priced per row.

  5. 05

    Pass the linkedin_url from the search result into email_finder rather than reconstructing name plus domain. Search gives you the LinkedIn URL; it is the stronger input at the same price.

  6. 06

    Branch leg three on leg two's success field, not on the status code.

    A finder miss is a 200 and the verifier has nothing to verify.

  7. 07

    Deduplicate against rows you already own before leg two.

    The search leg does not know what is in your CRM and will happily return people you emailed last quarter.

Example
# Leg 1 — search. Per-result pricing: every row returned bills,
# whether or not you keep it. limit and page are both required.
curl -s https://api.richapi.ai/api/v1/people_search \
  -H "x-api-key: $RICHAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "job_title": ["VP Engineering", "Head of Platform"],
    "industry": ["Software Development"],
    "employee_size_start": 200,
    "employee_size_end": 2000,
    "location": ["United States"],
    "limit": 100,
    "page": 0
  }'

# Filter here, in your own code, before spending 5 credits a row.

# Leg 2 — find. Waterfall: a miss is 200, success:false, billed:false, 0 credits.
curl -s https://api.richapi.ai/api/v1/email_finder \
  -H "x-api-key: $RICHAPI_KEY" \
  -H "content-type: application/json" \
  -d '{"linkedin_url": "https://www.linkedin.com/in/dana-weiss"}'

# Leg 3 — verify, only on rows leg 2 resolved.
curl -s https://api.richapi.ai/api/v1/email_verifier \
  -H "x-api-key: $RICHAPI_KEY" \
  -H "content-type: application/json" \
  -d '{"email": "dana.weiss@acme.com"}'

People search to email waterfall: one billing model per leg

Three calls: /people_search, /email_finder, /email_verifier. Two billing models between them, and if you only internalise one thing from this page, make it which leg charges you for rows you end up deleting.

/people_search bills per result, on every row it returns, whether you use it or not. 0.1 credits per result. It is not a waterfall endpoint and there is no free-miss case. Pull 2,000 profiles and discard 800, you paid for 2,000.

/email_finder and /email_verifier are waterfall endpoints. sources run cheapest-first; if none return data you get a 2xx with success: false, billed: false, and zero credits. Misses on those two legs are genuinely free. waterfall email then verify has that pair in detail.

Model it on a real list size

Numbers are meaningless on a per-result endpoint without a stated count, so here is one. 2,000 profiles pulled, 1,200 kept after filtering, 60% finder hit rate.

Leg Priced on Volume Credits
people_search @ 0.1/result every row returned 2,000 200
email_finder @ 5/call rows that resolved 720 of 1,200 3,600
email_verifier @ 2/call addresses found 720 1,440
Total 5,240

720 verified addresses. The search leg is 200 credits of 5,240, under 4%.

Which is the interesting part. The search is nearly free and the filtering is where the money is. Every row you let through to leg two is a 5-credit bet at your hit rate. Tighten the filter from 2,000 to 1,200 and you save 800 × 5 × 0.6 = 2,400 credits, twelve times what the whole search cost. Loosen your ICP to "see what comes back" and you pay for it two legs later.

So: search broadly if you like, it's cheap. Then be ruthless before leg two.

Getting the filters right before you spend anything

/search_reference_data costs 0 credits and returns the valid filter labels: seniority levels, industries, functions. Call it first. An industry string you invented returns an empty page, and while an empty page bills nothing on a per-result endpoint, the hour you spend wondering why isn't free.

/geo_id_search at 0.01 credits turns "San Francisco" into a LinkedIn Geo ID if you want precision beyond free-text location matching.

Both are covered in gtm data utilities along with the rest of the plumbing endpoints.

Paging, which is where the surprises live

limit and page are both required, and page is zero-based. Set limit small on the first pull. Look at twenty rows, confirm your filters mean what you think they mean, then widen.

The mistake is treating the first query as a rehearsal. On a per-result endpoint it isn't; it's a charge. It's a small charge, which is exactly why people run six exploratory queries at limit: 500 before noticing.

Feed the LinkedIn URL forward

Search results carry a LinkedIn profile URL. Pass that to /email_finder as linkedin_url rather than reassembling first_name + last_name + company_domain from the row. Same price, better resolution, and it sidesteps the domain problem entirely, which matters because turning a company name into a domain is its own unsolved step and domain clean then company enrich explains why.

The failure mode: re-searching instead of resuming

The expensive bug here is in the loop, not the finder leg.

A script pages through people_search, dies at page 7 of 20, and gets restarted from page 0. Pages 0–6 are fetched again and billed again. Per-result pricing means the retry cost is proportional to how far you got, so the longer the run, the worse the restart.

Write each page to disk as you fetch it and resume from the highest page you have. It's the same discipline as any paginated ingest and people skip it because 0.1 credits sounds like nothing until it's 0.1 × 3,500 twice.

The quieter bug is skipping the dedupe against your existing contacts. The search leg has no idea what's in your CRM. It will return the person you emailed in March, you'll spend 5 credits confirming an address you already have, and the only place that shows up is the invoice.

The receipt on search to email

The two waterfall legs return an execution_log: the source attempts on that request, each with a status. people_search does not; it isn't a waterfall and there's no source chain to log.

Where search to email goes wrong

No prospecting UI. This is an API and a list you keep yourself; if you want a grid to click around in, we don't have one. No intent data, no scoring, no sending. The chain ends with verified addresses in your store.

And no de-dupe against your CRM, because we don't connect to your CRM. That's your join.

Search to email FAQ

Does a search that returns nothing cost anything? Per-result pricing with zero results means zero rows billed. But it's not a waterfall endpoint, so don't generalise that to "misses are free" the way it's true for the finder.

Can I filter by domain instead of industry? Yes, people_search takes a domain array, which is the move when you already have target accounts and need people at them.

Why is page zero-based? It is. Check your first pull against your second and make sure you didn't skip or duplicate a hundred rows.

Is 0.1 credits per result the same as 0.1 credits per useful result? No, and that's the whole point of the filtering section. You pay for what's returned.

How do I test the chain cheaply? 100 free credits covers a small search plus a couple of finder calls. Use limit: 10.

Where to go after search to email

people search for the filter reference, list build and verify for the shorter version of this play, phone append after email hit to add numbers on top, gtm data utilities for the reference-data and geo lookups, and use cases for the rest. Tiers on pricing.

100 free credits, no card. Run one limit: 10 search and see the per-result billing on your own account before you write the paging loop.

FAQ

Frequently asked

Per-result pricing with zero results means zero rows billed. But it's not a waterfall endpoint, so don't generalise that to "misses are free" the way it's true for the finder.
Yes, `people_search` takes a `domain` array, which is the move when you already have target accounts and need people at them.
It is. Check your first pull against your second and make sure you didn't skip or duplicate a hundred rows.
No, and that's the whole point of the filtering section. You pay for what's returned.
100 free credits covers a small search plus a couple of finder calls. Use `limit: 10`.

More playbooks

Related playbooks

One key per client: what that buys an agency, and what it does notIssue a named API key per client, revoke any one of them without touching the others, and read usage attributed per key with a CSV export. What does not exist: per-client credit budgets, billed sub-accounts, and per-key spend caps. All credits come from one team balance, so a runaway job on one client's key spends the whole agency's credits. Budget enforcement lives in your scheduler, not in ours.Phone Append After an Email Hit: The 25-Credit Call That's Free When It MissesFind the email first, then append a phone number only to the rows that resolved. Both legs are waterfall endpoints, so both return `billed: false` and cost zero when sources find nothing. At 25 credits, the phone call is the most expensive in the catalog, which is exactly why the miss-free rule carries most of the value here.Turn a list of emails into enriched LinkedIn profilesResolve each email to a LinkedIn profile URL with find_linkedin_url_by_email, then enrich that URL with enrich_profile. Two calls, two charges. Neither one is a waterfall endpoint, so both bill on any 2xx — including a lookup that resolves nothing.Signal-Based Prospecting: Build an Account List From Jobs, Ads and PostsStart from something a company did this month (a job post, a running ad, a LinkedIn post) and turn it into an account list, then find and verify contacts on it. The signal endpoints bill per result on any 2xx; only the email_finder and email_verifier legs at the end are miss-free.