Skip to main content
A bulk email finder job finds deliverable work emails for a list of people in a single asynchronous job. Submit a list of LinkedIn profile URLs, or a list of rows with a name and company domain; OrbiSearch processes them in the background and returns a verified result for each. This guide uses the credit-metered endpoints. On an unlimited plan, the same workflow applies at the /v1/unlimited/bulk-lookup paths with an Unlimited key; rows draw on your daily cap instead of credits.

When to use the bulk email finder

  • LinkedIn lists: turn a list of LinkedIn profile URLs into reachable work emails.
  • List enrichment: turn a CSV of names + companies into a list of reachable emails.
  • Lead research at scale: research a target list once, instead of one address at a time.
  • Keeping a list current: people change jobs, so search your LinkedIn profile URLs again every few months to find each person’s current work email.
To find one person’s email on demand, use the single email finder. For verifying a list of email addresses you already have, use bulk verification.

How the bulk email finder works

1

Submit a job

Send a POST request to /v1/bulk-lookup with an input array of rows. Every row is a linkedin_url, or every row is a (first_name, last_name, domain) object; one job uses one kind. OrbiSearch returns a job_id immediately and begins processing in the background. Credits are deducted upfront for the unique row count.
2

Poll for status

Use GET /v1/bulk-lookup/{job_id} to check the job’s progress. Poll every 10–30 seconds until status becomes completed.
3

Retrieve results

Once the job is completed, fetch results with GET /v1/bulk-lookup/{job_id}/results. Results are paginated. Page through them with limit and offset.

Submitting a job

Send your list of people in the JSON body. Each row needs a domain and at least one of first_name and last_name. To search by LinkedIn profile URL instead, send a linkedin_url on every row (see LinkedIn profile URLs).
OrbiSearch responds with a job ID and the deduplicated row count:
OrbiSearch deduplicates the input array automatically (case-insensitive on first name + last name + domain, and on the profile for LinkedIn URLs, so two forms of the same profile URL count once). If your list has duplicates, you are only charged for the unique rows.

Checking job status

Poll GET /v1/bulk-lookup/{job_id} to track progress.
While the job is running, the response looks like this:
status is running until every row has been processed, at which point it becomes completed and finished_at is populated. The summary object updates live as rows complete, so you can show progress to your end user before the job is fully done.

Retrieving results

Once status is completed, fetch the full results. Use limit and offset to page through them. The default limit is 50 and the maximum is 500.
Each row in results has the same shape as a single email finder response:
When email is null, OrbiSearch could not find a deliverable address for that person at that domain, so don’t send to them there.

LinkedIn profile URLs

A job can search by LinkedIn profile URL instead of a name and domain. Send a linkedin_url on every row:
One job uses one kind of input: every row a linkedin_url, or every row a name and domain. A list that mixes the two is rejected with 422 before anything is charged, and the error names the first row of the other kind. To search both kinds of list, submit two jobs. What to expect for LinkedIn rows:
  • Results carry the same extra fields as a single search by LinkedIn URL: linkedin_url, full_name, employer_name, employer_linkedin_url, and all_emails. In a name and domain job these fields are null.
  • Substatuses: besides deliverable and no_address_found, a LinkedIn row can end as profile_not_found (a correctly formed profile URL that is not a valid profile, for example mistyped or no longer in use), no_current_employer (we couldn’t identify a current employer for this person) or no_company_website (the employer has no company website we could identify; if you know it, resubmit the row by name and domain). All three are charged.
  • Invalid URLs are not rejected. A row whose value isn’t a LinkedIn profile URL at all (for example a company page URL or plain text) is returned in the results with substatus: invalid_linkedin_url and credits_consumed: 0, and the rest of the job runs normally. It counts toward total_rows, but not toward the credits charged at submit.
  • temporarily_unavailable: in rare cases we can’t complete a row. It’s returned with this substatus, and you can resubmit it in a new job.

Pricing

Each unique row costs 1 credit, deducted upfront when you submit the job, whether it’s a LinkedIn URL or a name and domain. Every returned row is charged, except a row with substatus: invalid_linkedin_url, which is free. Refunds are issued only when OrbiSearch infrastructure cannot accept or process the submission itself. In that case the upfront charge is reversed and no job is created.

Limits and rate limits

  • Maximum 10,000 rows per submission. Split larger lists across multiple jobs.
  • This endpoint shares the 20 requests per second per account limit with the rest of the /v1/* API.

Complete example

Python