The fastest way to find a real estate broker's email is to look it up in a contact database, not to guess it. Search by brokerage domain and title, enrich the person, then read the email status before you send. This guide does that against LeadOcean with curl and spends 2 records.
Examples use placeholders (Acme Realty, acme-realty.com, Jane Doe). Swap in your own domain.
TL;DR
- Broker emails come from three places: a database lookup, a pattern guess at the brokerage domain, or the brokerage's own agent pages and state license lookups. Only the first gives you a deliverability status.
- Filter by
titleBroker and a real estateindustry, enrich withreveal_email, and send only toverifiedorcatch_all_validaddresses. - Takes about 10 minutes and spends 2 of the 1,000 free records. Sizing the audience first costs nothing.
Prerequisites
- A LeadOcean account. The free plan gives 1,000 records one-off, no card: register here.
- An API key from the app, exported as
$LEADOCEAN_API_KEY. curlandjq.
export LEADOCEAN_API_KEY="paste-your-key-here"Every request goes to https://api.leadocean.io with the header x-api-key. A free key has both scopes, search and enrich, at 5 requests a second.
Step 1: Size the broker list before you pull it
Send count=true and limit=1 as query parameters and the call returns a total without spending a record. Filters go in a flat JSON body, and every filter is an array of strings.
curl -s -X POST "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": ["Broker"],
"industry": ["Real Estate Agents and Brokers", "Real Estate"],
"country": ["US"]
}' | jq '.meta'The title filter is a keyword match, so "Broker", "Managing Broker" and "Broker Associate" all count. Wrap a value in brackets, "[Broker]", to match the exact title only. Real estate has no clean seniority ladder: in the count below, most brokers carry the owner or entry seniority, so a jobLevel filter drops many of them. Filter on title and industry instead.
meta.total is capped at 100,000, and meta.totalIsExact tells you whether it is a floor. Enum values are exact strings: use leadocean_list_enum_values or GET /v1/enums to check them.
Step 2: Search for the broker at one brokerage
Add the brokerage's domain to find the broker at that office. Each person returned costs one record, so keep limit small.
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-realty.com"],
"title": ["Broker"],
"limit": 1
}' > brokers.json
jq '.data | length' brokers.jsonSearch rows are thin: they carry has_email and has_phone flags, not the address itself. Read the title in the row before you spend a record on enrichment.
Large franchises list hundreds of licensees under one domain, and a franchise domain is rarely the office's own. For a small independent shop, the broker of record is usually the owner. Raise limit to 5 and pick the managing broker.
Step 3: Enrich the person to get the email
Each search row carries an id at meta.source_ids.person_id. Send it back to enrich that exact person. Enrich takes exactly one of linkedin_url, email, phone or person_id.
PID=$(jq -r '.data[0].meta.source_ids.person_id' brokers.json)
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"person_id\": \"$PID\", \"reveal_email\": true}" > person.jsonThis costs one record. reveal_email costs nothing extra and returns every email we hold for that person. If we hold nothing, you get a 404 and no charge. There is no lookup by name plus domain: search first, then enrich by person_id.
Step 4: Verify before you send
Read email_status and send only to addresses worth sending to. A verified or catch_all_valid status is safe. A catch_all status means the domain accepts everything, so the mailbox may not exist.
jq -r '.data.contact_data.contact_emails[]
| select(.status == "verified" or .status == "catch_all_valid")
| .email' person.jsonSome brokers use a personal webmail address next to the office one. Check the type field: work is the brokerage address, personal is not. Bounced emails are not refunded, so treat every status other than the two above as a no-send.
Step 5: Use a pattern only when the lookup finds nothing
When the broker is not in the data, guess at the brokerage domain, then verify the guess before you send. Four patterns cover most small-office mail setups:
first.last@acme-realty.com jane.doe@acme-realty.com
flast@acme-realty.com jdoe@acme-realty.com
first@acme-realty.com jane@acme-realty.com
firstl@acme-realty.com janed@acme-realty.comFind the pattern from any other agent address on the brokerage's site, then apply it to the broker's name. Never send to a guessed address that has not been verified. A guess at a catch-all domain always looks valid and tells you nothing.
Role addresses such as info@ or listings@ carry the role status and reach a front desk, not the broker. Skip them.
Step 6: Pull the whole list as a CSV
For a list rather than one person, start an export. POST /v1/exports takes up to 50,000 rows a request and 500,000 a day. Each row costs one record. Bulk CSV export is not on the Free plan: it starts on Solo at $97 a month.
curl -s -X POST "https://api.leadocean.io/v1/exports" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "brokers-us",
"filters": {
"title": ["Broker"],
"industry": ["Real Estate Agents and Brokers", "Real Estate"],
"country": ["US"],
"emailStatus": ["verified", "catch_all_valid"]
},
"limit": 1000,
"preset": "full"
}'Poll GET /v1/exports/{id}, then download from GET /v1/exports/{id}/download. The app's Exports page does the same with a filter builder, a column picker and the record price before you start. It needs no code.
What you get
The Step 1 count is free. The free MCP tool leadocean_count_leads ran these filters on 2026-10-21: title Broker, industry Real Estate Agents and Brokers or Real Estate, split by salesRegion. It counts people with a verified, catch_all_valid or catch_all email by default, so these are mailable counts.
| Region | Mailable brokers (title Broker, real estate industries, 2026-10-21) |
|---|---|
| Worldwide | 114,628 |
| NORAM | 91,863 |
| EMEA | 1,494 |
| LATAM | 738 |
| APAC | 567 |
The four regions sum to 94,662, less than the worldwide figure, because some people carry no region. The worldwide count spans 24,925 distinct companies, and the same filters match 412,817 people before the email filter. Each call returned totalIsExact: true and credits: 0. The REST search stops counting at 100,000, so the worldwide figure shows as a floor there. The MCP count is exact.
Coverage is a US story: 88,095 of the worldwide mailable brokers sit in the US and 3,728 in Canada. 88,473 of the 114,628 carry the owner seniority, so a broker list is largely a list of small business owners.
A record-level response has the shape below (response shape from the API reference, placeholder values):
{
"success": true,
"data": {
"profile_data": { "profile_full_name": "Jane Doe", "profile_headline": "Managing Broker at Acme Realty" },
"contact_data": {
"has_email": true,
"email_status": "verified",
"contact_emails": [
{ "email": "jane.doe@acme-realty.com", "type": "work", "status": "verified" }
]
}
},
"meta": { "source": "leadocean" }
}Each record carries its own fetched_at date, and the dataset refreshes monthly. Check the date on anything you plan to act on.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Re-export $LEADOCEAN_API_KEY and check the header name. Retrying will not help |
| 402 | Out of records. On Free the 1,000 are a one-off allowance | Move to Solo at $97 a month, or lower limit. Paid plans slow down at their fair-use pace instead of answering 402 |
| 429 | Over the plan's rate limit: 5 requests a second on Free, 200 on Agency | Honour the Retry-After header and back off |
Empty data | A filter value is not an exact enum string | List the allowed values with GET /v1/enums and copy one |
| 404 on enrich | We hold nothing for that person | No charge. Search again, or try the pattern route in Step 5 |
| Export refused | Over 50,000 rows a request, or over 500,000 rows a day | Split the export into several requests, or wait for the reset |
FAQ
Where do real estate broker emails come from?
From a contact database, from a pattern guess at the brokerage domain, or from public pages such as agent directories and the brokerage's own site. Only a database lookup returns a deliverability status. Guesses and scraped addresses need verifying before you send.
How many broker emails can I get for free?
The free plan gives 1,000 records one-off with no card. One search row costs one record and one enrichment costs one more, so a verified address for one broker costs about 2 records. Sizing the audience with count=true is free.
Can I find a broker's email from their name and brokerage?
Not in one call. Search by domain or companyName with the title filter, then enrich the match by person_id.
Why does a broker email bounce?
Usually the address was guessed, the broker moved brokerages, or the domain is catch-all and the mailbox never existed. Read email_status and the record's fetched_at date before you send. Bounced emails are not refunded.
Where do I go next?
For property owners rather than brokers, read email finder for real estate. The same recipe works for VP of Sales and VP of Marketing at larger firms. Solo is $97 a month if you outgrow the free records: see pricing.
Find your first real estate broker email with a free API key
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →