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

How-to guide

How to Use a Job Posting API for Outbound (With LeadOcean)

A job posting API tells you who is hiring. It does not tell you who to email. Here is the short recipe that closes that gap, with real queries and output.

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

TL;DR

  • A job posting API returns open roles by company. LeadOcean does not sell job postings. It answers the next question: who owns the hire, and what is their checked work email.
  • The recipe takes about 20 minutes the first time. It spends about 4 records per company, so 1,000 free records cover roughly 250 companies.
  • Sizing calls are free. Run them before every search, and only spend records on companies you will actually email.

What a job posting API is

A job posting API lets you query open roles programmatically instead of scraping career pages. People Data Labs announced one in April 2026 as a beta. Its launch post says postings come from company career pages, refresh daily, and can be filtered by company, role and location. Access is by request through the account team or a sign-up form (People Data Labs, April 2026, checked October 2026).

The launch post does not publish a schema, a price or rate limits. Read the vendor docs for those before you build on it. Other sources work too: a feed you already pay for, an ATS board, or a CSV you export by hand. This guide only needs one thing from them: a list of company domains with a role title.

Hiring data is a timing signal. It says a team has budget and a gap. It does not say who to talk to, and that is the job of the people data layer.

Prerequisites

  • A list of postings with a company domain and a role title, from any source. Ten rows is enough to start.
  • A LeadOcean account and key from app.leadocean.io. The free plan has no card and 1,000 records, one-off. Free keys get both the search and enrich scopes.
  • The key in your shell as $LEADOCEAN_API_KEY, plus curl and jq.
bash
export LEADOCEAN_API_KEY="paste-your-key-here"

Step 1: Normalise the postings to domain, team and level

Reduce each posting to three values: the company domain, the team that owns the role, and the level of the person who owns the hire. The owner is usually one level above the role. A Senior Backend Engineer posting points to an Engineering Manager or Director.

csv
domain,posting_title,team,owner_level
acme.com,Senior Backend Engineer,Engineering,"Director,VP"
example.com,Account Executive,Sales & Business Development,"Manager,Director"
example.org,Data Analyst,Information Technology,"Manager,Director"

The team values must match LeadOcean's jobFunction list exactly. Check them for free before you map anything.

bash
curl -s "https://api.leadocean.io/v1/enums/job_function" \
  -H "x-api-key: $LEADOCEAN_API_KEY" | jq

A wrong spelling returns nothing. Sales & Business Development works. Sales does not.

Step 2: Size the owners for free

Ask how many people hold that seat at the company before you spend a record. A search with count=true as a query parameter and limit at 1 is a free sizing call.

bash
curl -s -X POST "https://api.leadocean.io/v1/people/search?count=true" \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{
    "domain": ["acme.com"],
    "jobFunction": ["Engineering"],
    "jobLevel": ["Director", "VP"],
    "limit": 1
  }' | jq '.meta'

meta.total is capped at 100,000, which does not matter at one company. A zero means LeadOcean holds nobody at that level there. Drop the company and keep the records.

To size a whole list of target companies instead, use GET /v1/companies/count. It takes the company-search filters, returns an exact total with breakdowns, and costs nothing.

Step 3: Search the owners

Run the same filters without count. Each person returned costs one record, so keep limit at 3.

bash
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
  -d '{
    "domain": ["acme.com"],
    "jobFunction": ["Engineering"],
    "jobLevel": ["Director", "VP"],
    "limit": 3
  }' | jq -c '.data[] | {person_id: .meta.source_ids.person_id}'

Rows are thin: name, headline and current role. Pick the person whose headline fits the posting. At a 30-person company that is often the VP. At a 3,000-person company it is the Director closest to the team.

You can also match the posting title against profile text with q. It searches names, titles, headlines and job descriptions on the person's profile. That finds people who already do the job you are hiring for, which is a good opener for an email.

Step 4: Get the work email

Send the person_id to the work email endpoint. It returns one checked address at the person's current employer, or data: null.

bash
curl -s -G "https://api.leadocean.io/v2/people/email/work" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "person_id=PERSON_ID_FROM_STEP_3" | jq

Only verified, catch_all_valid or catch_all addresses come back. The call costs one record whether it finds one or not. LeadOcean gives no refund or credit-back for bounced emails, so read status before you send.

Step 5: Run the list

Loop the file from Step 1. The half-second sleep keeps two calls per row under the 5 requests a second on Free.

bash
tail -n +2 postings.csv | while IFS=, read -r domain title rest; do
  id=$(curl -s -X POST "https://api.leadocean.io/v1/people/search" \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
    -d "{\"domain\": [\"$domain\"], \"jobLevel\": [\"Director\", \"VP\"], \"limit\": 1}" \
    | jq -r '.data[0].meta.source_ids.person_id // empty')
  [ -z "$id" ] && continue
  curl -s -G "https://api.leadocean.io/v2/people/email/work" \
    -H "x-api-key: $LEADOCEAN_API_KEY" \
    --data-urlencode "person_id=$id" \
  | jq -c --arg d "$domain" --arg t "$title" '{domain: $d, posting: $t, email: .data.email, status: .data.status}'
  sleep 0.5
done > leads.jsonl

This takes the top row per domain and does not filter by team. Read ten results before you trust it, then add jobFunction per row.

For hundreds of companies, export instead. POST /v1/exports takes the same filters and writes one CSV, up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free. Solo at $97 a month includes it (pricing, October 2026). The app does the same on its Exports page and shows the record price before you start.

What you get

This sizing run is real. We ran it on 2026-10-21 with the free leadocean_count_leads tool, which spends 0 records. The query: Engineering people at Director or VP level in the US. The total counts people with a verified, catch-all valid or catch-all address.

json
{
  "total": 90487,
  "totalIsExact": true,
  "totalAll": 183736,
  "distinctCompanies": 29163,
  "unsupportedFilters": []
}

Read it as: 29,163 US companies have at least one such person in LeadOcean, and 90,487 of those people are mailable. That is the pool a posting for an engineering role draws from.

The next block is the response shape from the API reference. Every value is a placeholder, not a real record.

json
{
  "success": true,
  "data": {
    "email": "jane.doe@acme.com",
    "status": "verified",
    "verified_batch_date": "2026-09-20"
  }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-key headerCopy the key again from the app and check $LEADOCEAN_API_KEY is exported
429Above the plan's rate limit: 5 requests a second on Free, 200 on AgencyWait the Retry-After seconds, add a sleep, or move up a plan
402Records spent. Free is 1,000, one-offCheck GET /v1/account, then pick a paid plan on pricing
Empty dataA filter value is not an exact enum string, for example Sales instead of Sales & Business DevelopmentLook the value up with GET /v1/enums/job_function
data: null on work emailNo checked address for that personTry the next person from Step 3. The call still cost one record
Export refusedThe request is over 50,000 rows or the 500,000 a day ceiling, or the plan has no bulk exportSplit the request across days, or use Solo or above

FAQ

Does LeadOcean have a job posting API?

No. LeadOcean holds people and company data, not open roles. Use a posting source for the signal and LeadOcean for the owner and the email. A person's past and current roles are in the enrich response, but that is career history, not an open vacancy.

Which job posting API should I use?

Use the one that covers your roles and regions at a price you can see. People Data Labs has a beta and sells access through its team (People Data Labs, April 2026). If you only need a few hundred companies a month, a hand-built list from ATS boards is cheaper and often fresher.

How many records does this cost?

About 4 per company: up to 3 search rows and 1 work-email lookup. Counts and company sizing are free. An enrichment that finds nothing is free, but a work-email call that finds nothing still costs one record.

Can I monitor for new hires instead of new postings?

Yes, from the people side. See job change and company monitoring with an API. For the manual version of this recipe, see how to find an email from job postings.

What is an API?

An interface that lets one program ask another for data over HTTP. Our glossary entry covers the basics.

Turn your hiring signals into checked work emails

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

Get your free API key →