If you're building software for the real estate industry, finding one
agent is easy. Building a product that needs thousands of agent records
is a different problem.
You may need to search across states, keep contact information in a
consistent schema, paginate through large result sets, respect API
quotas, and integrate data into a CRM or internal application.
USAgentLeads provides a REST API for
programmatic access to its U.S. real estate agent contact database. At
the time of writing, the broader dataset contains more than 1.16 million
contacts across all 50 states. Records center on four fields: name,
email, phone, and state.
The API keeps the developer surface deliberately simple: API-key
authentication, one main agents endpoint, state filtering, name or email
search, pagination, quotas, and usage analytics.
Why Use an API Instead of a CSV?
A CSV is great when you need a static list. An API becomes more useful
when agent data is part of an application workflow.
User selects California
↓
Backend queries agent data
↓
Application applies its own logic
↓
Matching agents appear in the UI
↓
Selected records enter a workflow
Potential use cases include:
- PropTech applications
- CRM enrichment
- lead generation platforms
- brokerage recruiting tools
- mortgage and title software
- marketing agency dashboards
- internal sales systems
- market research tools
The API Model
The public API example uses:
GET /api/v1/agents
A basic request:
curl -H "X-API-Key: YOUR_API_KEY" \
"https://usagentleads.com/api/v1/agents?state=CA&page=1&pageSize=25"
A response follows this general shape:
{
"data": [
{
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "(310) 555-0100",
"state": "California"
}
],
"count": 42318,
"page": 1,
"totalPages": 1693,
"quota": {
"used": 147,
"limit": 10000
}
}
The response contains both records and metadata needed for pagination
and quota management.
Authentication
Requests use an API key in the X-API-Key header:
X-API-Key: YOUR_API_KEY
USAgentLeads says keys are SHA-256 hashed on its side, support instant
revocation, and accounts can maintain up to three active keys.
That makes it practical to separate environments:
Key 1 → Production
Key 2 → Staging
Key 3 → Internal scripts
Keep keys server-side. Never expose them in frontend JavaScript.
A safer architecture is:
Browser
↓
Your backend
↓
USAgentLeads API
Store the credential in an environment variable:
US_AGENT_LEADS_API_KEY=...
Querying Agents by State
State filtering is useful because many real estate workflows are
inherently geographic.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://usagentleads.com/api/v1/agents?state=FL&page=1&pageSize=25"
A mortgage company may operate in only six states. A brokerage
recruiting platform may run campaigns state by state. A PropTech startup
may launch in Florida before expanding nationwide.
Instead of loading the entire U.S. dataset and filtering it yourself,
request the market your application needs.
Search by Name or Email
The API also supports searching by name or email.
That enables workflows such as CRM enrichment:
Existing CRM record
↓
Search agent API
↓
Potential match
↓
Validate identity
↓
Attach available contact fields
Names are not unique, so don't blindly merge the first result. Use any
additional context your application has before updating a record.
Building a Small JavaScript Client
const BASE_URL = "https://usagentleads.com/api/v1";
async function getAgents({
state,
page = 1,
pageSize = 25
}) {
const params = new URLSearchParams({
page: String(page),
pageSize: String(pageSize)
});
if (state) params.set("state", state);
const response = await fetch(
`${BASE_URL}/agents?${params}`,
{
headers: {
"X-API-Key": process.env.US_AGENT_LEADS_API_KEY
}
}
);
if (!response.ok) {
throw new Error(
`USAgentLeads API returned ${response.status}`
);
}
return response.json();
}
Then:
const result = await getAgents({
state: "CA",
page: 1,
pageSize: 25
});
console.log(result.data);
console.log(result.count);
console.log(result.totalPages);
console.log(result.quota);
A TypeScript Model
interface Agent {
name: string;
email?: string | null;
phone?: string | null;
state: string;
}
interface ApiQuota {
used: number;
limit: number;
}
interface AgentResponse {
data: Agent[];
count: number;
page: number;
totalPages: number;
quota: ApiQuota;
}
Treat contact fields defensively. Real-world professional data can
contain missing values, and your application should handle them
gracefully.
Pagination
Large states can contain tens of thousands of records, so design around
pagination.
async function* iterateAgents(state) {
let page = 1;
while (true) {
const result = await getAgents({
state,
page,
pageSize: 25
});
for (const agent of result.data) {
yield agent;
}
if (page >= result.totalPages) break;
page++;
}
}
Usage:
for await (const agent of iterateAgents("TX")) {
await processAgent(agent);
}
For production jobs, add checkpoints, retries, deduplication, idempotent
writes, structured logs, quota monitoring, and graceful cancellation.
Rate Limits and Quotas
The current Pro API plan advertises:
10,000 API requests/month
60 requests/minute
Avoid sending hundreds of requests simultaneously. Use a queue or
concurrency limiter for bulk jobs.
The API response also exposes quota usage:
{
"quota": {
"used": 147,
"limit": 10000
}
}
That makes quota-aware applications straightforward:
const usageRatio =
result.quota.used / result.quota.limit;
if (usageRatio > 0.8) {
await notifyOps(
"USAgentLeads API quota is above 80%"
);
}
You can also expose consumption in an internal dashboard.
API Key Management
With multiple active keys and per-key analytics, workloads can be
separated:
production-web
↓
Customer-facing searches
production-worker
↓
Background enrichment
staging
↓
Development and QA
A safe rotation process is:
1. Generate a new key
2. Deploy the new key
3. Verify traffic
4. Revoke the old key
Example: CRM Enrichment
Suppose a CRM receives:
{
"name": "Jane Smith",
"state": "CA",
"email": null,
"phone": null
}
An enrichment worker could:
New CRM record
↓
Search USAgentLeads
↓
Find candidate records
↓
Validate identity
↓
Add available email and phone
↓
Save enrichment metadata
Store provenance too:
{
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "(310) 555-0100",
"state": "CA",
"enrichment_source": "usagentleads",
"enriched_at": "2026-08-11T12:00:00Z"
}
Provenance helps with debugging, refreshes, and suppression workflows.
Example: Brokerage Recruiting
A recruiting dashboard could let a manager choose a state, search
available agents, and add selected records to a recruiting workflow.
USAgentLeads API
|
v
Backend Service
|
+---------+---------+
| |
v v
Search UI Sync Worker
| |
+---------+---------+
|
v
PostgreSQL
|
+---------+---------+
| |
v v
CRM Campaign Tool
Your database stores application-specific information such as campaign
status, assigned recruiter, last contact, reply status, notes, and
suppression status.
The external API supplies contact data. Your product supplies the
workflow.
Example: PropTech Lead Routing
A SaaS application could combine agent data with proprietary signals:
Agent record
+
Customer territory
+
Historical engagement
+
Campaign activity
=
Internal lead score
The API doesn't need to solve the entire business problem. It can be one
building block inside a larger system.
Example: Market Research
A nationwide agent dataset can also support analysis without contacting
anyone.
Possible questions include:
- Which states contain the largest agent populations?
- Where should a PropTech product launch first?
- How large is the reachable market in each state?
- Which states justify dedicated sales resources?
You could combine agent counts with other datasets:
Agent population
+
Housing transactions
+
Median home price
+
Company conversion data
=
Market attractiveness score
Data Freshness
Contact data ages. People switch brokerages, change phone numbers, stop
using addresses, or leave the industry.
USAgentLeads says its dataset was refreshed in August 2026 and that
cleanup passes remove duplicates and malformed contacts.
Your application should still record when source data entered your
system:
CREATE TABLE agent_contacts (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT,
phone TEXT,
state TEXT,
source TEXT NOT NULL,
source_synced_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
That makes stale local records easier to identify later.
Contact Data Is Not the Same as Outreach Permission
This distinction matters.
USAgentLeads says its records come from publicly available professional
sources including state licensing boards, public MLS directories,
professional association registries, brokerage websites, and realtor
listing platforms.
The sender remains responsible for applicable outreach rules.
If your application sends outreach, build a suppression layer:
CREATE TABLE suppressions (
id BIGSERIAL PRIMARY KEY,
email TEXT UNIQUE,
reason TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Then check it before sending:
if (await isSuppressed(agent.email)) {
return;
}
await sendCampaignMessage(agent);
Suppression data should take precedence over newly imported source data.
If someone opts out, don't re-add them merely because they appear in a
later API result.
A Production Architecture
For a larger application, avoid letting every frontend request hit the
upstream API directly.
USAgentLeads API
|
v
Data Access Layer
|
+----------+----------+
| |
v v
Redis Cache Job Queue
| |
v v
API App Sync Workers
| |
+----------+----------+
|
v
PostgreSQL
|
+-------------+-------------+
| | |
v v v
Search CRM Sync Analytics
This gives you centralized rate-limit handling, caching, consistent
errors, easier key rotation, background synchronization, and audit logs.
Cache Repeated Queries
If multiple users request the same state and page within a short period,
you may not need repeated upstream calls.
const cacheKey =
`agents:${state}:${page}:${pageSize}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const result = await getAgents({
state,
page,
pageSize
});
await redis.set(
cacheKey,
JSON.stringify(result),
{ EX: 300 }
);
return result;
Even a short cache can reduce quota consumption in a busy application.
API vs. Local Database
Should you query the API live or synchronize records into your own
database?
It depends on the product.
Use live API calls when:
- searches are occasional
- you want fresher upstream data
- you don't need complex local joins
- storing the full dataset isn't necessary
Synchronize selected records locally when:
- contacts become part of customer workflows
- you need your own metadata
- you need fast joins and analytics
- users add agents to campaigns or territories
- you need audit history
A hybrid architecture is often best:
Search → API
Selected agents → Local DB
Workflow metadata → Local DB
Refresh selected records → API
Final Thoughts
The interesting part of a real estate agent API isn't the complexity of
the REST interface. In fact, simpler is usually better.
The value is turning a large, fragmented professional dataset into
something your application can query predictably.
With USAgentLeads, developers get a
straightforward REST surface around nationwide real estate agent contact
data, with API-key authentication, state filtering, name and email
search, pagination, quotas, rate limiting, key management, and usage
analytics.
That makes it useful as a building block for:
- CRM enrichment
- PropTech applications
- brokerage recruiting systems
- mortgage and title workflows
- lead routing
- market research
- internal sales tools
The best architecture is usually not to make the data provider your
application.
Use the API as an input.
Add your own workflow, scoring, analytics, permissions, compliance
controls, and domain-specific logic on top.
That's where the product becomes yours.
For current endpoint details and access, see the USAgentLeads
API.
Top comments (0)