API Documentation
The LocaMapHQ public API finds local business leads by city and industry. Use it from scripts, agents, or any HTTP client to search, list, and export leads within your credit balance. Prefer a terminal workflow instead of raw HTTP calls? The LocaMapHQ CLI wraps this same API for city and industry searches, saved leads, and CSV export.
Authentication
All endpoints except /health and /meta require a Bearer API key.
Authorization: Bearer lmhq_live_YOUR_KEY_HERECreate a key at /dashboard/settings/api-keys. The raw key is shown exactly once on creation and cannot be recovered later. Give it a name so you can identify it, and revoke it if it is ever compromised.
Credits
Search costs 1 credit per business returned. The charge is based on what is actually found, up to your requested limit. A search that returns no results, or that fails upstream, charges nothing.
All other endpoints are free: health, metadata, balance check, listing saved leads, and CSV export.
Before running a search, call GET /api/public/v1/credits to check the balance. The balance is a guide, not an exact quote, since the final charge depends on how many businesses are found.
Add credits
Purchase credit packs at /pricing. See current pack sizes and prices in the GET /api/public/v1/meta response.
Rate limits
Limits are per API key. On serverless deployments with multiple concurrent instances, effective limits may be higher because each instance maintains its own counters.
| Group | Limit | Applies to |
|---|---|---|
| permissive | Effectively open | /health, /meta |
| general | 60 / minute | /credits, /leads/saved |
| search | 10 / minute | /leads/search |
| export | 20 / minute | /leads/export |
When a limit is exceeded the response is 429 with a Retry-After header giving seconds until the window resets.
Endpoints
/api/public/v1/healthLiveness check.
/api/public/v1/metaService metadata, pricing, and onboarding URLs.
/api/public/v1/creditsCurrent credit balance.
/api/public/v1/leads/savedList stored leads, paginated.
/api/public/v1/leads/searchFind local businesses by city and trade.
/api/public/v1/leads/exportExport a search as CSV.
POST /api/public/v1/leads/search
Find local businesses by city and trade. Returns business name, category, address, phone, rating, review-volume signal, and whether the business has a website. Charges 1 credit per result actually found.
Request body
{
"city": "Austin", // required
"industry": "plumber", // required
"limit": 25, // optional, one of 10 / 25 / 50 / 100, default 10
"country": "US", // optional, default "US"
"name": "My search" // optional label
}Response (200)
{
"search_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"prospects_found": 23,
"credits_used": 23,
"remaining_credits": 227
}Retrieve results with GET /api/public/v1/leads/saved?search_id=<id>.
GET /api/public/v1/leads/saved
Returns stored prospects paginated. Pass ?search_id= to filter to one search.
Query parameters
| Param | Default | Notes |
|---|---|---|
| limit | 20 | Max 100. |
| offset | 0 | Pagination offset. |
| search_id | -- | UUID. Filter to a specific search. |
Code examples
All examples use the placeholder key lmhq_live_YOUR_KEY_HERE. Replace it with your actual key from the dashboard.
Search -- curl
curl -X POST https://www.locamaphq.com/api/public/v1/leads/search \
-H "Authorization: Bearer lmhq_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"city":"Austin","industry":"plumber","limit":25}'Search -- JavaScript
const response = await fetch(
'https://www.locamaphq.com/api/public/v1/leads/search',
{
method: 'POST',
headers: {
'Authorization': 'Bearer lmhq_live_YOUR_KEY_HERE',
'Content-Type': 'application/json',
},
body: JSON.stringify({ city: 'Austin', industry: 'plumber', limit: 25 }),
}
);
const data = await response.json();
console.log(
`Found ${data.prospects_found} leads, used ${data.credits_used} credits.`
);
// Retrieve the actual results
const results = await fetch(
`https://www.locamaphq.com/api/public/v1/leads/saved?search_id=${data.search_id}`,
{ headers: { 'Authorization': 'Bearer lmhq_live_YOUR_KEY_HERE' } }
);
const { prospects } = await results.json();Search -- Python
import requests
API_KEY = "lmhq_live_YOUR_KEY_HERE"
BASE = "https://www.locamaphq.com/api/public/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Run a search
response = requests.post(
f"{BASE}/leads/search",
headers={**HEADERS, "Content-Type": "application/json"},
json={"city": "Austin", "industry": "plumber", "limit": 25},
)
data = response.json()
print(f"Found {data['prospects_found']} leads, used {data['credits_used']} credits.")
# Retrieve results
results = requests.get(
f"{BASE}/leads/saved",
headers=HEADERS,
params={"search_id": data["search_id"]},
)
for p in results.json()["prospects"]:
website = p["website_url"] or "(no website)"
print(f"{p['business_name']} -- {p['phone']} -- {website}")Error codes
All errors return JSON in the standard envelope:
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry after the window resets." } }| Code | HTTP | When |
|---|---|---|
| unauthorized | 401 | Authorization header missing or malformed. |
| invalid_api_key | 401 | Key not found in the database. |
| revoked_api_key | 401 | Key was revoked. Create a new key. |
| invalid_request | 400 | Missing or invalid request parameter. |
| insufficient_credits | 402 | Not enough credits for the requested search. |
| rate_limited | 429 | Too many requests. Check the Retry-After header. |
| provider_unavailable | 503 | Search provider is temporarily unavailable. No credits charged. |
| internal_error | 500 | Unexpected server error. No credits charged if no results were saved. |