Property records API
Look up recorded owners, sales and mortgage history by address. API access is included in every paid plan.
Get an API keyAuthentication
Create a key in your workspace’s API keys page. Send it as a bearer token. Keys belong to a workspace and use the same monthly credits as browser lookups.
Authorization: Bearer wh_live_your_keyKeep keys on your server. Reading results requires lookup:read; submitting lookups requires lookup:write. You can revoke a key from your workspace.
Look up addresses
/api/v1/batchesSend up to 1,000 addresses in a batch. Formatting and common abbreviations are normalized before matching. Include city and state, or ZIP, whenever possible.
curl https://whohouse.io/api/v1/batches \
-H 'Authorization: Bearer wh_live_your_key' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: your-unique-batch-id' \
-d '{"addresses":["3785 n 192nd ter elkhorn , ne"]}'The API returns 202 Accepted with a job ID and status. Use a stable Idempotency-Key when retrying the same request to avoid creating a second job.
{ "id": "job_example", "status": "queued", "total": 1 }For one address, use POST /api/v1/lookup with {"address":"104 Example St, Omaha, NE"}. It returns a job in the same format and requests the full record, consuming credits on a successful owner match.
Source responses are cached server-side for up to 24 hours. A fresh cache hit avoids a new provider request. Job acceptance and result readiness are separate timings; cold lookups depend on the source. No fixed response-time SLA is offered.
Get results
/api/v1/batches/{id}Poll with a short delay until the job’s status is completed. Results preserve input order. Each address has its own status, so a missing owner record does not discard the rest of your batch.
{
"job": {
"id": "job_example",
"status": "completed",
"total": 1,
"completed": 1,
"matched": 1
},
"items": [
{
"index": 0,
"input": "104 Example St, Omaha, NE",
"status": "matched",
"result": {
"address": "104 Example St, Omaha, NE",
"owner": {
"name": "[recorded name]",
"relationship": "recorded_owner",
"label": "Recorded owner",
"source": "County property record"
},
"property": {
"propertyType": "Single-family home"
},
"source": {
"name": "County property record",
"updatedAt": null,
"retrievedAt": "2026-09-12T12:00:00Z"
}
}
}
],
"pagination": {
"limit": 100,
"offset": 0,
"total": 1
}
}sales contains recorded buyers, sellers, prices and sale dates. mortgages contains dated source loan records, including borrowers, lenders, amounts, status, rates and balances when supplied. valuation holds source estimates; photos holds available image URLs and attribution. Missing fields are omitted, not filled with guesses. A past sale may contain only a date; it does not establish a chain of title.
Results are paginated: use ?offset=0&limit=100, with a maximum limit of 1,000. Download a CSV from GET /api/v1/batches/{id}/export.csv. The sales, mortgages, valuation, photos and source_by_field CSV columns contain JSON so repeated records and their dates are preserved.
owner_unavailable means property facts were found but no owner name was returned. not_found, ambiguous, and invalid mean the address needs review. Only successful owner lookups use credits. Repeated matches to the same property in a workspace’s billing period don’t count again; missing owners, ambiguous matches, and unsuccessful lookups are free. A submission reserves credits while it runs, so a batch must fit within the available balance. Unused reservations are released when the work finishes.
Source dates are reported separately from retrieval dates. A recorded buyer is identified as a buyer, and a normalized address does not establish current ownership. Results are retained for 30 days, up to 500 completed jobs per workspace.
Errors and limits
| Status | Meaning |
|---|---|
400 | Check the address list and request format. |
401 | The API key is missing or invalid. |
402 | The workspace’s lookup allowance is exhausted. |
403 | Check workspace access, membership, key scopes, and plan eligibility. |
409 | An idempotency key was reused with a different request. |
429 | A request limit has been reached. Follow the response details before retrying. |
503 | A source is temporarily unavailable. |
Use bounded concurrency and retry temporary failures with a delay. Individual item failures appear in the job results. There are no automatic overage charges.
Compare plans