API

A read-only API over HTTPS. Each account holder gets an API key, and the base URL comes with it. New data is ready every morning after the county files are pulled.

Put the API on it — Get a test keyRead the API docs

Test keys open the sample. Working keys belong to account holders.

How delivery works

  1. Every morning we pull the county, court and city files, tie each record to its property and owner, and publish the result.
  2. Each record has an updated date, the day it last changed. Ask for since= the last date you hold and you get only what's new or changed.
  3. Daily change files list the same changes as gzip NDJSON (one JSON record per line), with {"id": ..., "removed": true} lines for records that dropped off (for example, taxes paid).
  4. Full snapshots of each county and record type are available any time.

Authentication

Send your key in the x-api-key header on every request. Requests without a valid key are refused. Each key has its own rate limit and daily quota, and every request is logged. HTTPS only.

curl -H "x-api-key: YOUR_KEY" "https://BASE_URL/v1/coverage"

Endpoints

RequestWhat it returns
GET /v1/coverageCounties, record types, counts and dates you can pull
GET /v1/signals?county=Travis&signal=tax_suit&since=2026-01-01Records, newest changes included, up to 500 per page. Pass next_cursor back as cursor= for the next page
GET /v1/signals?county=Dallas&signal=tax_suit&min_amount=5000&lender_eligible=yesThe same, narrowed by filters. Add count_only=true for just the number of matches
GET /v1/filtersEvery filter, its values, and how many records in each county carry it
GET /v1/exports/{date}Short-lived download links (15 minutes) for that day's change files and the current full snapshots. date can be latest
GET /v1/parcels/{county}/{parcel_id}One property: owner, exemptions, tax status and every record we deliver for it

Record types (signal): tax_delinquent, tax_suit, tax_sale, code_violation, foreclosure, bankruptcy, eviction, probate, divorce, civil.

Filters

Filters narrow GET /v1/signals on our side, so you download only the records you want. Every filter you add must match (they combine with AND). Inside zip and property_type, a comma list means any of them.

FilterValuesWhat it means
min_amount, max_amountdollars, e.g. 2000Total taxes owed (tax.taxes_owed). It includes penalty and interest only where tax.penalty_interest_included is true; in other counties it is the base tax, so the payoff is higher
homesteadyes / noHomestead exemption
over65yes / noOver-65 or over-65 surviving spouse exemption
disabledyes / noDisabled-person exemption
veteranyes / noDisabled-veteran exemption
deferralyes / noA tax deferral (Tax Code 33.06) is on file
lender_eligibleyes / nolender.lender_eligible: none of the bars to a property tax loan we can see
has_suityes / noA tax suit was filed (in suit, judgment, or an earlier suit)
property_typeresidential, land, commercial, mobile_home, otherFrom the appraisal district's state code: residential = houses, multifamily and builder inventory; land = vacant lots, farm and ranch land and rural acreage; commercial = commercial and industrial buildings and land; mobile_home = mobile homes; other = minerals, business personal property, utilities, exempt
absenteeyes / noThe owner's mailing address is not the property
out_of_stateyes / noThe owner's mailing address is outside Texas
min_years_delinquentwhole number, e.g. 2At least this many tax years carry an unpaid balance
zip5-digit ZIP, comma listThe property's ZIP code
count_onlytrueReturn only the number of matching records, for quoting

When a record doesn't have the field. Not every county publishes every field (Tarrant's tax file, for example, has no usable exemption codes). A record with no known value for a filtered field is left out, except when the filter is no: then unknown counts as no. So homestead=no keeps records whose exemptions are unknown. GET /v1/filters shows, for each county, how many records have each field.

Paging with filters. Pass next_cursor back as cursor= and keep every other parameter the same. If you change a filter, the old cursor is refused (400); start again without it. A page can hold fewer than limit records; keep going until next_cursor is empty.

Filtered downloads. The daily files from /v1/exports are whole files and can't be filtered. For a filtered download, page through /v1/signals with your filters.

Examples

# How many Tarrant delinquent accounts owe $2,000 or more, have no homestead, and are lender-eligible?
curl -H "x-api-key: YOUR_KEY" "https://BASE_URL/v1/signals?county=Tarrant&signal=tax_delinquent&min_amount=2000&homestead=no&lender_eligible=yes&count_only=true"

# Dallas tax suits on houses, $5,000 or more owed, lender-eligible
curl -H "x-api-key: YOUR_KEY" "https://BASE_URL/v1/signals?county=Dallas&signal=tax_suit&property_type=residential&min_amount=5000&lender_eligible=yes"

# Harris accounts 2+ years behind in two ZIP codes, no over-65 exemption, changed since November 1
curl -H "x-api-key: YOUR_KEY" "https://BASE_URL/v1/signals?county=Harris&signal=tax_delinquent&zip=77084,77449&min_years_delinquent=2&over65=no&since=2026-11-01"

Sample record

Every value below is made up.

{
  "id": "0000example0000example0000example0000000",
  "signal": "tax_suit",
  "county": "Example",
  "filed_date": "2026-01-15",
  "case_number": "TX-0000-EXAMPLE",
  "status": "in_suit",
  "amount": 1234.56,
  "parties": [{"name": "EXAMPLE OWNER LLC"}],
  "property_address": "123 SAMPLE ST",
  "match": {"parcel_id": "000000000", "method": "parcel", "confidence": "confirmed"},
  "owner": {"name": "EXAMPLE OWNER LLC", "mail_address": "PO BOX 0000", "mail_city": "ANYTOWN",
            "mail_state": "TX", "mail_zip": "00000", "absentee": true, "out_of_state": false},
  "property": {"situs_address": "123 SAMPLE ST", "property_use": "A1", "year_built": 1999,
               "market_value": 100000, "deed_date": "2010-01-01"},
  "exemptions": {"codes": ["HS"], "homestead": true, "over_65": false, "disabled": false,
                 "disabled_veteran": false, "tax_deferral": false},
  "tax": {"taxes_owed": 1234.56, "first_year_delinquent": "2024", "suit_status": "in_suit",
          "suit_number": "TX-0000-EXAMPLE", "judgment_date": null, "bankruptcy": false, "deferral": false},
  "lender": {"lender_eligible": true, "ineligible_reasons": [], "notices": []},
  "loans": null,
  "source": {"system": "Agentix RE Solutions", "dataset": "county tax records"},
  "first_seen": "2026-01-20T11:00:00Z",
  "updated": "2026-01-20"
}

source is always {"system": "Agentix RE Solutions", "dataset": ...}, where dataset is the kind of record: county tax records, county court records, county foreclosure notices, city code enforcement records, county property records or bankruptcy court records. A few city code records also carry an attribution line that the city's data license requires.

Loans on the record

Records tied to a property can carry a loans list: what the county records say about the mortgage on it. It comes only from county records: posted trustee-sale (foreclosure) notices, and the lender that escrows the taxes on a tax or appraisal roll. GET /v1/parcels returns the same list, and GET /v1/coverage shows with_loans and with_loan_amount counts for each county and record type.

Every number is {value, unit, source}, and source tells you how we know it:

FieldWhat it is
lender, servicerAs named in the recorded notice or the tax roll
deed_of_trust_date, deed_of_trust_instrumentFrom the notice, when it states them
original_amountThe original principal, only when the notice states it
rateA Texas public record never shows the note rate. With a deed of trust date, it is the Freddie Mac Primary Mortgage Market Survey 30-year average for that week, labeled ESTIMATE. With no date, it is 7%, labeled ASSUMPTION: no rate on record
est_balanceOnly when the original amount and date are both known: paid as scheduled over 30 years at the rate above. Labeled ESTIMATE; it ignores missed payments, modifications and arrears
from_recordThe kind of public record the loan came from, as a plain category (for example county foreclosure notices (notice posted 2026-10-05))

A record with no county loan facts has "loans": null, which means unknown, not "no loan". Rate estimates: Freddie Mac, Primary Mortgage Market Survey.

{
  "id": "0000example0000example0000example0000001",
  "signal": "foreclosure",
  "county": "Example",
  "filed_date": "2026-10-05",
  "property_address": "456 SAMPLE DR",
  "match": {"parcel_id": "000000001", "method": "address", "confidence": "confirmed"},
  "loans": [{
    "lender": "EXAMPLE MORTGAGE COMPANY",
    "servicer": "EXAMPLE LOAN SERVICING",
    "deed_of_trust_date": "2019-06-14",
    "deed_of_trust_instrument": "2019-0000000",
    "original_amount": {"value": 200000, "unit": "usd", "source": "Stated in the recorded notice"},
    "rate": {"value": 3.82, "unit": "pct", "source": "ESTIMATE: Freddie Mac, Primary Mortgage Market Survey (30-year fixed average) for the week of 2019-06-13, when the deed of trust was signed; the loan's actual rate is not on public record"},
    "est_balance": {"value": 169444, "unit": "usd", "source": "ESTIMATE: original amount paid as scheduled over 30 years at the rate above (89 payments); ignores missed payments, modifications and arrears"},
    "term_years": {"value": 30, "unit": "years", "source": "ASSUMPTION: term not on record"},
    "from_record": "county foreclosure notices (notice posted 2026-10-05)",
    "record_id": "0000example0000example0000example0000001"
  }],
  "source": {"system": "Agentix RE Solutions", "dataset": "county foreclosure notices"},
  "updated": "2026-11-05"
}

Sample page

{
  "county": "Example",
  "signal": "tax_suit",
  "since": "2026-01-01",
  "filters": {},
  "total": 6981,
  "count": 500,
  "next_cursor": "eyJleGFtcGxlIjoidHJ1ZSJ9",
  "records": [ ... ]
}

Errors

CodeMeaning
400A parameter is missing or wrong, or a filter isn't one we offer (the message lists the valid ones), or a cursor is reused with different filters
403Missing or invalid API key
404No such export date or no records for that parcel
410The data was refreshed after your cursor was issued. Start again with since=
429Rate limit or daily quota reached

Permitted use

Keys are issued only to businesses that agree to our terms: real estate marketing, lending outreach and research only, and never for credit, employment, insurance or tenant-screening eligibility decisions.

Keys

Keys come in two kinds. A test key is an evaluation courtesy: ask us, and if your firm is a qualified Texas property tax lender we issue one by hand — it opens the sample records and the coverage view, nothing more. Working keys belong to account holders: when your firm signs and your account is active, your key opens the live feed — the full delivered records for your counties, the daily change files and the full snapshots. There is no self-serve key creation, on purpose: the feed is licensed per firm, and the key is how we hold that line. Ask for a test key, or contact us with any questions.