API: Property Pulls and Enrichment
Pull filtered property lists and enrich single addresses from the property database — 1 credit per record, free records on subscriptions.
The property endpoints run on our own nationwide property database — 130M+ properties covering every county, refreshed monthly. Every record costs a flat 1 creditand includes everything: address, owner and mailing address, property details, estimated value, equity, DTV, open liens and lender, deed and sale history, distress flags, quick-list flags, and the motivation score. Subscribers get their plan's monthly credit amount as free records every billing period (a 10,000-credit plan is 10,000 free records per period), and you are only charged for records actually delivered.
Use the v2 endpoints for new work — they take the same filters object as the dashboard's Data Pulling builder. The original v1 property endpoints keep working unchanged in shape; see v1 compatibility below. Both share your API key and the error envelope, and either pairs with bulk skip tracing to go from filters to phone numbers entirely via API.
v2 at a glance
| Endpoint | Purpose | Cost |
|---|---|---|
POST /api/v2/property-pulls/count | How many properties match a filters object | Free |
POST /api/v2/property-pulls | Pull up to 25,000 matching records | 1 credit / record after free records |
GET /api/v2/property-pulls · /{id} · /{id}/results | List pulls, check one, page through its records | Free |
GET /api/v2/property-pulls/quota | Your free-record allowance this period | Free |
GET /api/v2/property-pulls/list-stacks | The List Stack slugs you can filter by | Free |
POST /api/v2/enrich | Full record for a single address | 1 credit (or a free record) per match |
The filters object
Every v2 pull and count takes a filters object. Only area.state is required; every other group is optional and can be omitted entirely. Ranges are {min?, max?} (min must not exceed max), tri-state flags are true / false / omitted, and dates are YYYY-MM-DD. Unknown fields anywhere inside filters (the message names the path, e.g. filters.equity.debtBurdn: unknown field), values out of range, or more entries than a list allows return 422 validation_error. Need the exact county, city or ZIP keys? GET /v2/areas (below) resolves them.
| Group | Fields |
|---|---|
area | state (2-letter, required); counties as 5-digit FIPS codes (max 50); cities as upper-case names (max 20); zips 5-digit (max 100) — OR-ed together; bbox [west, south, east, north] optionally narrows to a map viewport. |
lists | slugs — List Stack slugs from the list-stacks endpoint (max 10), e.g. absentee, high_equity, pre_foreclosure, mortgage_maturing; match "all" (default) or "any"; params tunes a parameterised stack per slug, e.g. { "mortgage_maturing": { "window_months": 12 } } (names, ranges and defaults come from the list-stacks endpoint). |
property | types: any of sfr, condo, townhouse, multi, mobile, land, commercial. Ranges: estValue ($), beds, baths, sqft, yearBuilt, lotAcres, units, stories, monthsSinceRenovation. At least: openPermits, stalePermitMonths. Flags: hasPool, mobileHome. |
owner | Flags: occupied, absentee, corporate (true = entity-owned — LLC, trust or company; false = individual), outOfState, inherited, units24 (2–4 units). ownershipBuckets: any of <1, 1-3, 3-5, 5-10, 10-20, 20+ years. Ranges: yearsOwned, portfolioCount. At least: sold12m (properties the owner sold in the last 12 months). |
equity | Ranges: equityPct (−100 to 100), ltv (debt-to-value %, shown as DTV in the dashboard), openLienCount, lien1Rate (%), estConfidence (0–100), debtBurdenPct (open debt plus liens and judgments as a share of value), monthsToMaturity, recentDebtAdded ($ recorded in the last 12 months). equityBuckets: any of 0, 1-20, 21-40, 41-60, 61-80, 80+. Flags: freeAndClear, lien1Adjustable, lien1Heloc, cashOutRefi. (estValue now lives under property; the old place is still accepted.) |
distress | fcDocTypes: foreclosure document types (max 10, the observed set). auctionWithinDays: 30, 90, 365 or "all". Range: monthsSinceLien. At least: fcEpisodes. Flag: fcReleased. Pre-foreclosure, tax delinquent, vacant and involuntary lien are list stacks (pre_foreclosure, tax_delinquent, vacant, invol_lien). |
sales | lastSaleDate {from?, to?}; lastSalePrice ($); appreciationPct (value vs last purchase price, %). Flags: cashPurchase, recentBuyer (bought within 2 years), longTermOwner (10+ years), nonArmsLength. |
score | motivationMin: minimum seller motivation score, 0–100. |
exclude | previouslyPulled: true skips anything this account pulled in the last 30 days. |
sort | by: motivation_score (default), est_value, equity_pct, years_owned, last_sale_date, debt_burden_pct, appreciation_pct, months_to_maturity; dir: desc (default) or asc. Decides which records are pulled when more match than count. |
POST /v2/property-pulls/count — check the match count (free)
Send a filters object and get the number of matching properties before spending anything — the same figure the dashboard shows as you build a list. total.kind is exact when the count finished, capped when more than the counting cap matched (the value is the cap), or estimate when a planner estimate was used. With exclude.previouslyPulled set, already_pulled is the overlap with your last 30 days of pulls and new_since_last_pull is what a pull would actually deliver.
curl -X POST https://www.acquired-data.com/api/v2/property-pulls/count \
-H "Authorization: Bearer ad_live_XXXX" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"area": { "state": "PA", "counties": ["42101"] },
"lists": { "slugs": ["absentee", "high_equity"], "match": "all" },
"score": { "motivationMin": 60 },
"exclude": { "previouslyPulled": true }
}
}'{
"total": { "value": 8412, "kind": "exact" },
"already_pulled": 512,
"new_since_last_pull": 7900,
"data_version": "2026-10"
}POST /v2/property-pulls — create a pull
Same filters object plus count (1–25,000) and an optional list_name. The pull runs synchronously — keep the connection open; a large pull can take a minute or two. If the connection drops, the pull still finishes server-side — poll GET /v2/property-pulls/{id}. Records pulled through the API also unlock free profile views in the dashboard and show up as pulled there.
curl -X POST https://www.acquired-data.com/api/v2/property-pulls \
-H "Authorization: Bearer ad_live_XXXX" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"area": { "state": "PA", "counties": ["42101"], "cities": [], "zips": [] },
"lists": { "slugs": ["absentee", "high_equity"], "match": "all" },
"property": { "types": ["sfr", "multi"], "beds": { "min": 2 } },
"owner": { "corporate": false },
"equity": { "estValue": { "min": 100000, "max": 600000 } },
"score": { "motivationMin": 60 },
"exclude": { "previouslyPulled": true },
"sort": { "by": "motivation_score", "dir": "desc" }
},
"count": 500,
"list_name": "philly-absentee-equity"
}'HTTP 201
{
"pull_id": "9b2c7e40-5d1a-4c3e-8f27-6b0d9e4a1c55",
"status": "complete",
"list_name": "philly-absentee-equity",
"requested_count": 500,
"matched_count": 8412,
"pulled_count": 500,
"free_records": 300,
"credits_charged": 200,
"credits_refunded": 0,
"price_per_record": 1,
"data_version": "2026-10",
"source": "api",
"filters": { "area": { "state": "PA", "counties": ["42101"], "cities": [], "zips": [] }, "...": "..." },
"created_at": "2026-10-13T18:00:01Z",
"completed_at": "2026-10-13T18:00:09Z",
"error_message": null,
"download_url": "https://www.acquired-data.com/storage/...signed-csv...",
"results_url": "https://www.acquired-data.com/api/v2/property-pulls/9b2c7e40-5d1a-4c3e-8f27-6b0d9e4a1c55/results"
}Here 500 records were delivered, 300 were covered by the period's free records, and 200 credits were charged. Errors: 402 insufficient_credits (balance below count minus your remaining free records), 422 validation_error (bad filters, unknown list slug, or count out of range), and 429 job_in_progress (another pull is already running on the account).
Listing pulls and fetching results
GET /v2/property-pulls— all pulls on the account (dashboard and API), newest first.page,per_page(default 20, max 100), optionalsourcefilter (api|app). Items have the same shape as the create response.GET /v2/property-pulls/{id}— status, counts, billing fields, the filters it ran with, and once complete a fresh signed CSVdownload_url(1 hour) plusresults_url.GET /v2/property-pulls/{id}/results— rows as flat JSON withpageandper_page(default 100, max 1,000). Each row is snake_case withproperty_idfirst, then keys likeaddress,owner_1_first_name,owner_mailing_address,estimated_value,estimated_equity,equity_percent,mortgage_balance,dtv,open_lien_count,lien_1_lender,last_sale_date,preforeclosure,motivation_score,years_owned,data_version. Requesting results before completion returns409 job_not_complete.- Extended records. Send
"columns": "extended"on a pull (or an enrich) and the CSV and the JSON rows gain the list-stack metrics and detail columns on top of the standard set: debt burden, months to maturity, appreciation, recent debt, cash-out refi, lien 1–4 amounts and due dates, foreclosure filing / release / episodes, involuntary lien detail, transfer detail, permit counts and dates, the owner's portfolio (property count, total value and debt, average equity, newest purchase, properties sold in 12 months), quick-list flags and month-over-month changes. The exact key list is on the API reference page in your dashboard. Same price.
GET /v2/areas — find county, city and ZIP keys
filters.area wants county FIPS codes, upper-case city names and ZIPs. GET /v2/areas?q= resolves a name prefix (or a 3–5 digit ZIP prefix) to those keys, optionally narrowed with state and kind (county, city or zip) — the same search as the dashboard's area picker.
{
"areas": [
{ "kind": "city", "key": "MEMPHIS", "label": "Memphis", "state": "TN", "property_count": 298412 },
{ "kind": "zip", "key": "38109", "label": "38109", "state": "TN", "property_count": 12044 }
]
}GET /v2/property-pulls/quota — your free records
Subscribers get their plan's monthly credit amount as free records each billing period. The quota endpoint tells you where you stand so you can predict what a pull will cost: remaining records are free, and anything beyond that is credit_per_record (1) each. Profile views charged in the dashboard count against the same allowance. Accounts without a subscription see subscribed: false and an allowance of 0.
{
"credit_per_record": 1,
"subscribed": true,
"allowance": 30000,
"used": 2590,
"remaining": 27410,
"period_start": "2026-10-06T00:00:00Z",
"period_end": "2026-11-03T00:00:00Z"
}GET /v2/property-pulls/list-stacks
Returns the named List Stacks you can put in filters.lists.slugs — the same presets as the dashboard, each with a side of buyers (who is buying: cash_buyers, recent_buyers, investors, likely_flip, multi_property_owners) or sellers (absentee, high_equity, free_and_clear, pre_foreclosure, tax_delinquent, vacant, inherited, tired_landlord, mortgage_maturing, portfolio_selloff, and more). Parameterised stacks list their knobs under params (name, kind, default, min, max, presets) — pass a value in filters.lists.params[slug][name] to tune the stack, otherwise the default applies. clauses are the conditions a property must meet. available is false for a stack whose definition is not live in the current data drop.
{
"list_stacks": [
{ "slug": "absentee", "name": "Absentee Owners", "group": "standard", "side": "sellers",
"description": "Owner mailing address differs from the property (vendor flag).", "available": true,
"params": [], "clauses": [] },
{ "slug": "mortgage_maturing", "name": "Recent Mortgage Maturity", "group": "differentiated", "side": "sellers",
"description": "Owners whose mortgage (any open lien) matures within the window.", "available": true,
"params": [
{ "name": "window_months", "kind": "months", "label": "Maturity window", "default": 24,
"min": 1, "max": 60, "step": 1, "unit": "mo", "presets": [6, 12, 18, 24] }
],
"clauses": [ { "key": "maturing", "label": "A mortgage matures within the window" } ] }
]
}From a pull to phone numbers
A completed pull can be skip-traced without downloading it: POST /v1/jobs with { "pull_id": "…", "add_ons": ["dnc"] }loads the pull's results, maps its columns automatically and runs the normal bulk job— the API version of the dashboard's "Skip trace this list".
Market Trends
Three read-only endpoints expose the Market Trends page's numbers for every county and ZIP: GET /v2/market/metrics (the metric catalogue), GET /v2/market/areas (one metric for every area of a state, or every county nationally, sortable) and GET /v2/market/areas/{kind}/{key} (one area's latest values, year-over-year changes and — on request — its time series). Each area response includes list_filters, a readyfilters object for the count and pull endpoints, so market research flows straight into a list. See the API reference in your dashboard for the fields.
Billing
- 1 credit per record, every dataset included — there are no add-ons or dataset upcharges on property data.
GET /pricingreportsproperty_pull: 1and aproperty_datablock with your free-record figures. - Free records on subscriptions.Each billing period your plan's monthly credit amount is also your free-record allowance. A pull uses free records first;
free_recordsin the response is how many it covered andcredits_chargedispulled_count − free_records. - Charged only for delivered records. Credits are held for the worst case when the pull starts and the difference is refunded automatically if fewer records match than
count; the response reports bothcredits_chargedandcredits_refunded. Counting is always free. - Enrichment is a one-record pull: 1 credit or one free record on a match, nothing on a miss.
POST /v2/enrich — single-address enrichment
Give POST /v2/enrich an address and it returns the full property record inline — the same keys as pull results — to fill gaps in your own data. street and state are required, plus either city or zip. exact_match is false when the hit came from address normalization rather than a literal match.
curl -X POST https://www.acquired-data.com/api/v2/enrich \
-H "Authorization: Bearer ad_live_XXXX" \
-H "Content-Type: application/json" \
-d '{
"address": { "street": "1234 Walnut St", "city": "Philadelphia", "state": "PA", "zip": "19107" }
}'{
"matched": true,
"property_id": "42101-0541234-00",
"exact_match": true,
"credits_charged": 0,
"free_record_used": true,
"property": {
"property_id": "42101-0541234-00",
"address": "1234 Walnut St", "city": "Philadelphia", "state": "PA", "zip": "19107",
"county": "Philadelphia", "apn": "054-123400", "property_type": "Single Family",
"bedrooms": "3", "bathrooms": "2", "living_square_feet": "1650", "year_built": "1925",
"owner_1_first_name": "Dana", "owner_1_last_name": "Reyes",
"owner_mailing_address": "88 Ocean Ave", "owner_mailing_city": "Cape May", "owner_mailing_state": "NJ",
"owner_type": "Individual", "owner_occupied": "false", "vacant": "false",
"estimated_value": "412000", "estimated_equity": "298000", "equity_percent": "72.3",
"mortgage_balance": "114000", "dtv": "27.7", "open_lien_count": "1", "lien_1_lender": "Example Bank",
"last_sale_date": "2009-06-30", "last_sale_price": "185000",
"preforeclosure": "false", "corporate_owned": "false", "free_and_clear": "false",
"motivation_score": "71", "years_owned": "17", "data_version": "2026-10"
}
}
// No match — nothing charged
{ "matched": false, "property_id": null, "credits_charged": 0, "free_record_used": false, "property": null }Errors: 402 insufficient_credits (no free records left and balance below 1 credit) and 422 validation_error (missing street/state, or neither city nor zip).
v1 compatibility
Integrations built on POST /api/v1/property-pulls and POST /api/v1/enrich keep working with their existing request bodies — the query object with state, counties, cities, zips, quicklists, the beds/baths/sqft/year_built/value ranges and property_types; the flat address/city/state/zip enrichment body; and GET /api/v1/property-pulls, /{id} and /{id}/results. They are now served from the same database, so what changed is:
- Price.
price_per_recordis always1, andcredits_chargedis records delivered minus the free records the pull used. The v1 shape does not break outfree_records— read the same pull fromGET /v2/property-pulls/{id}or checkGET /v2/property-pulls/quotaif you need that figure. datasetsis ignored. It is still accepted, but every record already includes valuation, liens and deed history, and responses returndatasets: [].countgoes up to 25,000 (previously 10,000).- Counties are resolved by name (
"Philadelphia"or"Philadelphia County"; 5-digit FIPS codes also work) against the database; an unknown county returns422 validation_errornaming it. - Quicklists map to List Stacks. Still supported:
absentee-owner,in-state-absentee-owner,out-of-state-absentee-owner,owner-occupied,high-equity,low-equity,free-and-clear,preforeclosure,notice-of-default,notice-of-sale,notice-of-lis-pendens,tax-default,involuntary-lien,vacant,vacant-lot,corporate-owned,trust-owned(treated as entity-owned),cash-buyer,tired-landlord,inherited,recently-sold,fix-and-flip. No longer supported — a request naming any of these returns422listing them:senior-owner,mailing-address-vacant,on-market,active-listing,expired-listing,has-hoa,listed-below-market-price. - Enrichment response. A hit returns
{ pull_id, matched: true, credits_charged (0 or 1), free_record_used, datasets: [], environment, property }wherepropertyis the full snake_case record with the same keys as pull results; a miss returnsmatched: falsewithcredits_charged: 0,pull_id: nullandproperty: null.
Everything else — pagination, download_url lifetimes, the 409 job_not_complete and 429 job_in_progress behaviour — is unchanged. When you next touch the integration, switching to v2 gets you the full filter set, free match counts and the quota endpoint.
Looking for who would buy a property rather than who owns it? See the buyer search API.
Keep reading
API Quickstart: Authentication, Sandbox, and Errors
Create an API key, make your first calls, and handle rate limits and the error envelope.
Read →APIAPI: Single Skip Trace
Look up one owner synchronously with POST /trace and get contact data back inline.
Read →APIAPI: Bulk Skip-Trace Jobs
Submit up to 10,000 rows as JSON or CSV, poll status, and fetch paginated results.
Read →