The Skip Trace API allows you to create skip trace tasks and retrieve their status. All requests must include a valid JWT token in the Authorization header.
https://landportal.com/wp-json/lp-rest-api/v1
All requests must include a JWT token:
Authorization: Bearer <JWT_TOKEN>
input_file or json_data must be providedinput_file, a fields mapping must be included{
"method": "create",
"input_file": "https://example.com/data.csv",
"has_header": true,
"fields": {
"last_name": "last_name",
"first_name": "first_name",
"mailing_address": "mailing_address",
"mailing_city": "mailing_city",
"mailing_state": "mailing_state",
"mailing_zip": "mailing_zip",
"property_address": "property_address",
"property_city": "property_city",
"property_state": "property_state",
"property_zip": "property_zip"
},
"emails_trace": false,
"demographics": false,
"test_mode": "true"
}
{
"method": "create",
"json_data": [
{
"last_name": "Smith",
"first_name": "John",
"mailing_address": "123 Main St",
"mailing_city": "New York",
"mailing_state": "NY",
"mailing_zip": "10001",
"property_address": "456 Oak Ave",
"property_city": "Brooklyn",
"property_state": "NY",
"property_zip": "11201"
}
],
"emails_trace": false,
"demographics": false,
"test_mode": "true"
}
{
"success": true,
"message": "Skip trace created successfully",
"data": {
"data_length": 100,
"input_file": "https://s3.amazonaws.com/bucket/skip-trace-files/uuid_userid_timestamp.csv",
"task_id": 12345,
"tokens_left": 950
}
}
"true" for testing purposes.
curl -X POST "https://landportal.com/wp-json/lp-rest-api/v1/skip-trace" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"method": "create",
"json_data": [{"last_name":"Smith","first_name":"John"}],
"test_mode": "true"
}'
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/skip-trace"
headers = {"Authorization": "Bearer <JWT_TOKEN>"}
payload = {
"method": "create",
"json_data": [{"last_name": "Smith", "first_name": "John"}],
"test_mode": "true"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const response = await fetch("https://landportal.com/wp-json/lp-rest-api/v1/skip-trace", {
method: "POST",
headers: {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
},
body: JSON.stringify({
method: "create",
json_data: [{ last_name: "Smith", first_name: "John" }],
test_mode: "true"
})
});
const data = await response.json();
console.log(data);
{
"method": "get",
"task_id": 12345
}
{
"success": true,
"message": "Skip trace data",
"data": {
"task_id": 12345,
"task_status": "completed",
"total_rows": 100,
"success_rows": 95,
"output_file_csv": "https://skip-trace.landportal.com/files/uuid_file.csv"
}
}
method — Must be "stop"task_id — The ID of the task to stop{
"method": "stop",
"task_id": 12345
}
{
"success": true,
"message": "Skip trace task stopped successfully",
"data": { "response_code": 200 }
}
curl --location 'https://landportal.com/wp-json/lp-rest-api/v1/skip-trace' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{"method":"stop","task_id":12345}'
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/skip-trace"
headers = {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
}
response = requests.post(url, json={"method": "stop", "task_id": 12345}, headers=headers)
print(response.json())
const response = await fetch("https://landportal.com/wp-json/lp-rest-api/v1/skip-trace", {
method: "POST",
headers: {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
},
body: JSON.stringify({ method: "stop", task_id: 12345 })
});
console.log(await response.json());
method — Must be "continue"task_id — The ID of the task to continue{
"method": "continue",
"task_id": 12345
}
{
"success": true,
"message": "Skip trace task continued successfully",
"data": { "response_code": 200 }
}
curl --location 'https://landportal.com/wp-json/lp-rest-api/v1/skip-trace' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{"method":"continue","task_id":12345}'
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/skip-trace"
headers = {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
}
response = requests.post(url, json={"method": "continue", "task_id": 12345}, headers=headers)
print(response.json())
const response = await fetch("https://landportal.com/wp-json/lp-rest-api/v1/skip-trace", {
method: "POST",
headers: {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
},
body: JSON.stringify({ method: "continue", task_id: 12345 })
});
console.log(await response.json());
Performs an instant, single-record skip trace: looks up contact data via Versium and scrubs returned phone numbers through TCP Litigator. No file or CSV is generated — the raw API responses are returned directly.
single_skip_trace_limit > 0 (decremented on each successful call; resets daily at midnight Eastern Time){
"method": "create_single",
"first": "John",
"last": "Smith",
"address": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
}
This API service accepts a consumer first and last name, and any other known consumer contact information. The more fields provided, the more accurate the match.
| Field | Type | Required | Description |
|---|---|---|---|
first | string | No | First name |
last | string | No | Last name |
address | string | No | A house/building number and street. Any address associated with the consumer improves match accuracy. |
city | string | No | City |
state | string | No | State (2-letter code, e.g. TX) |
zip | string | No | ZIP code |
{
"success": true,
"meta": { "daily_requests_left": 49 },
"data": {
"task_id": 12345,
"timestamp": "2026-04-10 14:00:00",
"first": "John",
"last": "Smith",
"address": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701",
"phones": [
{ "phone": "5125550100", "line_type": "Mobile", "dnc": false, "dnc_types": [] },
{ "phone": "5125550101", "line_type": "Landline", "dnc": true, "dnc_types": ["tcpa"] }
]
}
}
{
"success": false,
"message": "Single skip trace limit exhausted"
}
HTTP 403. The daily limit resets automatically at midnight Eastern Time.
curl --location 'https://landportal.com/wp-json/lp-rest-api/v1/skip-trace' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"method": "create_single",
"first": "John",
"last": "Smith",
"address": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
}'
{ "success": false, "message": "User not authenticated" }
{ "success": false, "message": "Input file or JSON data is required" }
{ "success": false, "message": "You are not authorized to get this skip trace" }
{ "success": false, "message": "Internal server error occurred" }
The Comp Reports API allows you to generate and retrieve comp reports for a given property. Report generation is asynchronous — use the GET endpoint to fetch the result once ready.
https://landportal.com/wp-json/lp-rest-api/v1
All requests must include a JWT token:
Authorization: Bearer <JWT_TOKEN>
comp_reports_limit > 0 (decremented on each successful call; resets daily at midnight Eastern Time)| Field | Type | Required | Description |
|---|---|---|---|
propertyid | string | Yes | Property ID from LandPortal database. |
fips | string | Yes | 5-digit FIPS code identifying the county. |
{
"propertyid": "12345678",
"fips": "12345"
}
{
"success": true,
"meta": { "daily_requests_left": 49 },
"data": {
"task_id": 4821,
"property_id": "12345678",
"fips": "12345",
"timestamp": "2026-04-10 00:00:00"
}
}
curl -X POST 'https://landportal.com/wp-json/lp-rest-api/v1/reports' \
-H 'Authorization: Bearer <JWT_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{"propertyid":"12345678","fips":"12345"}'
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/reports"
headers = {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
}
response = requests.post(url, json={"propertyid": "12345678", "fips": "12345"}, headers=headers)
print(response.json())
const response = await fetch("https://landportal.com/wp-json/lp-rest-api/v1/reports", {
method: "POST",
headers: {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
},
body: JSON.stringify({ propertyid: "12345678", fips: "12345" })
});
console.log(await response.json());
| Parameter | Type | Required | Description |
|---|---|---|---|
propertyid | string | Yes | Property ID from LandPortal database. |
fips | string | Yes | 5-digit FIPS code identifying the county. |
{
"success": true,
"data": {
"location": "County, State",
"address": "Property Street Address",
"apn": "Assessor Parcel Number",
"link": "https://landportal.com/?property=encoded_property_link",
"zipcode": 12345,
"usecode": 1006,
"landuse": "Property Land Use Description",
"size": "Property size in acres",
"land_locked": false,
"road_frontage": "Road frontage in feet",
"wetlands_cover_percentage": "Percentage of wetlands coverage",
"fema_cover_percentage": "Percentage of FEMA flood zone coverage",
"total_our_estimation_values_base": "Total estimated property value",
"price_acre_our_estimation_values_base": "Price per acre (our estimation)",
"price_acre_mean": "Mean price per acre",
"price_acre_county": "County average price per acre",
"report_id": 123,
"updated_at": "2026-04-10 10:30:00.000000"
}
}
curl -X GET 'https://landportal.com/wp-json/lp-rest-api/v1/reports?propertyid=12345678&fips=12345' \
-H 'Authorization: Bearer <JWT_TOKEN>'
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/reports"
headers = {"Authorization": "Bearer <JWT_TOKEN>"}
params = {"propertyid": "12345678", "fips": "12345"}
response = requests.get(url, params=params, headers=headers)
print(response.json())
const response = await fetch(
"https://landportal.com/wp-json/lp-rest-api/v1/reports?propertyid=12345678&fips=12345",
{ headers: { "Authorization": "Bearer <JWT_TOKEN>" } }
);
console.log(await response.json());
| Status | Message | Cause |
|---|---|---|
| 400 | propertyid and fips are required | Missing required parameters. |
| 400 | Wrong fips | No county database found for the given FIPS. |
| 400 | Report not found | No report exists for this property. |
| 403 | Comp report limit exhausted | Daily quota exhausted. |
| 403 | API access disabled | API access is disabled for this user. |
| 500 | Database error occurred | Internal server error. |
The Export API creates asynchronous CSV export tasks, tracks their status, and returns downloadable file links when processing is complete.
https://landportal.com/wp-json/lp-rest-api/v1
All requests must include a JWT token:
Authorization: Bearer <JWT_TOKEN>
POST /export: valid fips and propertyid arrays| Field | Type | Required | Description |
|---|---|---|---|
fips | array<string|number> | Yes | County FIPS list used to resolve source county tables. Each item must be a 5-digit FIPS code. |
propertyid | array<string|number> | Yes | Property IDs to export. Each item must be a positive bigint. |
Normalization: fips and propertyid values can be sent as strings or numbers. API normalizes them before task persistence.
Billing: 1 propertyid = 1 export token. Debit happens on successful task creation.
{
"fips": ["12103", "06037"],
"propertyid": [123456789, "987654321"]
}
{
"success": true,
"data": {
"task_id": 65432,
"export_tokens_left": 998,
"message": "Export task queued"
}
}
Personal cabinet behavior: Export task history in your account shows task metadata (status, counters, timestamps, links). Full input arrays are stored in the payload file; the cabinet provides a link/path to that payload file with complete fips/propertyid data.
curl -X POST "https://landportal.com/wp-json/lp-rest-api/v1/export" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"fips": ["12103", "06037"],
"propertyid": [123456789, "987654321"]
}'
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/export"
headers = {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
}
payload = {
"fips": ["12103", "06037"],
"propertyid": [123456789, "987654321"]
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const response = await fetch("https://landportal.com/wp-json/lp-rest-api/v1/export", {
method: "POST",
headers: {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
},
body: JSON.stringify({
fips: ["12103", "06037"],
propertyid: [123456789, "987654321"]
})
});
console.log(await response.json());
| Parameter | Type | Required | Description |
|---|---|---|---|
task_id | integer | Yes | Export task ID returned by POST /export. |
| Status | Description |
|---|---|
queued | Task is queued and waiting for worker pickup. |
processing | Worker is collecting data and building CSV output. |
completed | CSV is generated and uploaded; file_url is available. |
failed | Task failed. Check error_message for details. |
{
"success": true,
"data": {
"task_id": 65432,
"status": "processing"
}
}
{
"success": true,
"data": {
"task_id": 65432,
"status": "completed",
"file_url": "https://landportal-exports.s3.us-east-2.amazonaws.com/exports/api_export_65432.csv",
"rows": 2
}
}
curl -X GET "https://landportal.com/wp-json/lp-rest-api/v1/export?task_id=65432" \
-H "Authorization: Bearer <JWT_TOKEN>"
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number. Default: 1. |
per_page | integer | No | Page size. Default: 50, max: 200. |
{
"success": true,
"data": {
"tasks": [
{
"task_id": 65433,
"status": "completed",
"created_at": "2026-05-23 13:58:01",
"updated_at": "2026-05-23 13:58:45",
"rows": 2,
"file_url": "https://landportal-exports.s3.us-east-2.amazonaws.com/exports/api_export_65433.csv",
"error_message": false
},
{
"task_id": 65432,
"status": "processing",
"created_at": "2026-05-23 13:57:10",
"updated_at": "2026-05-23 13:57:15",
"rows": 0,
"file_url": "",
"error_message": false
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 17
}
}
}
pagination.total — total number of tasks for your account (not total pages). See the Technical Recommendations tab for pagination details.
curl -X GET "https://landportal.com/wp-json/lp-rest-api/v1/export/tasks?page=1&per_page=50" \
-H "Authorization: Bearer <JWT_TOKEN>"
| Status | Message | Cause |
|---|---|---|
| 400 | Invalid request body | Malformed JSON body. |
| 400 | fips must be an array | Missing or invalid fips. |
| 400 | propertyid must be an array | Missing or invalid propertyid. |
| 400 | task_id is required | Missing or invalid task_id in GET /export. |
| 403 | Insufficient export tokens limit | Not enough export tokens to create task. Error payload includes required_export_tokens and available_export_tokens. |
| 403 | You are not authorized to access this task | Task belongs to another user. |
| 404 | Task not found | Unknown task ID. |
| 500 | Failed to queue export task | Task persistence/scheduler failure. |
Returns detailed data for a single property record by Property ID and FIPS code. The set of returned fields is determined by the per-user and global field configuration in admin settings.
https://landportal.com/wp-json/lp-rest-api/v1
All requests must include a JWT token:
Authorization: Bearer <JWT_TOKEN>
single_property_limit is used first, then subscription export tokens when available)| Parameter | Type | Required | Description |
|---|---|---|---|
propertyid + fips | string + string | One of two | Primary lookup pair (Property ID + 5-digit FIPS). |
lat + lng | number + number | One of two | Alternative lookup pair by point. |
propertyid + fips are provided, they take precedence.lat + lng to resolve a property.Quota consumption order: the API consumes single_property_limit first; once it reaches 0, it consumes subscription export tokens (if available).
Meta counter: meta.requests_left is the combined remaining balance for this endpoint (daily single-property quota + available export tokens).
{
"success": true,
"meta": {
"requests_left": 49
},
"data": {
"property": {
"propertyid": "12345678",
"fips": "12345",
"address": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
}
}
}
curl -X GET "https://landportal.com/wp-json/lp-rest-api/v1/property-data?propertyid=12345678&fips=12345" \
-H "Authorization: Bearer <JWT_TOKEN>"
curl -X GET "https://landportal.com/wp-json/lp-rest-api/v1/property-data?lat=30.2672&lng=-97.7431" \
-H "Authorization: Bearer <JWT_TOKEN>"
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/property-data"
headers = {"Authorization": "Bearer <JWT_TOKEN>"}
params = {"propertyid": "12345678", "fips": "12345"}
response = requests.get(url, params=params, headers=headers)
print(response.json())
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/property-data"
headers = {"Authorization": "Bearer <JWT_TOKEN>"}
params = {"lat": 30.2672, "lng": -97.7431}
response = requests.get(url, params=params, headers=headers)
print(response.json())
const response = await fetch(
"https://landportal.com/wp-json/lp-rest-api/v1/property-data?propertyid=12345678&fips=12345",
{ headers: { "Authorization": "Bearer <JWT_TOKEN>" } }
);
console.log(await response.json());
const response = await fetch(
"https://landportal.com/wp-json/lp-rest-api/v1/property-data?lat=30.2672&lng=-97.7431",
{ headers: { "Authorization": "Bearer <JWT_TOKEN>" } }
);
console.log(await response.json());
| Status | Message | Cause |
|---|---|---|
| 400 | Either propertyid+fips or lat+lng is required | Missing required query parameters. |
| 400 | County not found | No database found for the given FIPS code. |
| 403 | Single property limit reached | Both daily single-property quota and export tokens are exhausted (or export tokens are unavailable). |
| 403 | API access disabled | API access is disabled for this user. |
| 404 | Property not found | No record for the given propertyid + fips. |
| 500 | Database error occurred | Internal server error. |
Apply advanced filters and return matching properties.
https://landportal.com/wp-json/lp-rest-api/v1
GET /filter-data/filters-list — available filters and examplesGET /filter-data/filter-values — values dictionary for a specific filterPOST /filter-data/filter — apply filters and return matching propertiesSource of truth: use GET /filter-data/filters-list to retrieve the latest supported filters, operators, and dynamic request examples.
Scope rule: filters.fips is required only when neither filters.polygon nor filters.bbox is provided.
FIPS condition: for filters.fips, comparison is optional and defaults to is.
FIPS value format: value can be either a single 5-digit FIPS string or an array of 5-digit FIPS strings.
Meta: skipped restricted filters are returned in meta.rejected_filters with key, value, and reason.
Filter endpoint counter: POST /filter-data/filter returns meta.requests_left.
Single Property counter: GET /property-data also returns meta.requests_left.
filter_data_limit: decremented by 1 only for successful responses with non-zero result set. Not decremented for overflow (count > 50000) or error responses.
Supported operator groups include boolean, condition, range, date, equals, and geometry filters (polygon, bbox).
Supported date formats: YYYY-MM-DD (ISO 8601, recommended) and legacy YYYYMMDD.
Supported comparisons: is_between, is_before, is_after, is.
Supported keys: percentage_of_land_with_flat_slope_0_05, sum_up_to_5, sum_up_to_10, sum_up_to_15.
Min-only usage: slope filters support using only value.min (without value.max).
Supported keys: currentsaleseller1fullname, ownername1full, ownername2full.
Matching behavior: partial and case-insensitive (owner-search style). You can pass part of a name (for example, "smith").
Comparisons: is and is_not.
{
"filters": {
"fips": {
"operator": "condition",
"comparison": "is",
"value": "39001"
},
"ownername1full": {
"operator": "condition",
"comparison": "is",
"value": "smith"
}
}
}
{
"filters": {
"fips": {
"operator": "condition",
"comparison": "is",
"value": "39001"
},
"currentsaleseller1fullname": {
"operator": "condition",
"comparison": "is_not",
"value": "holdings"
}
}
}
nulls FlagAccepted input forms: boolean (true/false), string ("true"/"false", "yes"/"no"), numeric (1/0), and numeric strings ("1"/"0").
Behavior: nulls: true includes records with missing/null date value; nulls: false returns only records that match the date condition.
{
"filters": {
"fips": {
"operator": "condition",
"comparison": "is",
"value": "39001"
},
"currentsalerecordingdate": {
"operator": "date",
"comparison": "is_between",
"value": {
"min": "2025-12-01",
"max": "2026-05-18"
},
"nulls": true
}
}
}
{
"filters": {
"fips": {
"operator": "condition",
"comparison": "is",
"value": ["39001", "39049", "39113"]
},
"vacant": {
"operator": "boolean",
"value": true
}
}
}
| Key | Value format | Description |
|---|---|---|
filters.polygon |
string or string[] | One or more polygons. Each ring is a comma-separated list of "lon lat" pairs (min 4 pairs). Single string or array of strings; semicolon-separated string also accepted. |
filters.bbox |
string | Bounding box as exactly 2 "lon lat" pairs separated by a comma: top-left and bottom-right. |
Scope: filters.fips is required only when neither filters.polygon nor filters.bbox is provided.
Multipolygon — semicolon-separated string: "ring1_coords;ring2_coords"
Multipolygon — array of strings: ["ring1_coords", "ring2_coords"]
Both formats produce the same Elasticsearch geo_shape multipolygon query. A single ring produces a polygon query.
{
"filters": {
"polygon": {
"value": "-83.9135 33.6435,-83.9169 33.6256,-83.9057 33.6193,-83.8946 33.6164,-83.9135 33.6435"
},
"vacant": { "operator": "boolean", "value": true }
}
}
{
"filters": {
"polygon": {
"value": [
"-83.9135 33.6435,-83.9169 33.6256,-83.9057 33.6193,-83.8946 33.6164,-83.9135 33.6435",
"-84.1020 33.7510,-84.1150 33.7310,-84.0940 33.7200,-84.0800 33.7350,-84.1020 33.7510"
]
}
}
}
{
"filters": {
"polygon": {
"value": "-83.9135 33.6435,-83.9169 33.6256,-83.9057 33.6193,-83.8946 33.6164,-83.9135 33.6435;-84.1020 33.7510,-84.1150 33.7310,-84.0940 33.7200,-84.0800 33.7350,-84.1020 33.7510"
}
}
}
These are top-level request body parameters, placed alongside filters (not inside it).
| Parameter | Type | Default | Description |
|---|---|---|---|
duplicates | boolean | true |
When false, deduplicates results by mailingfullstreetaddress, keeping the record with the largest lotsizeacres per unique address. |
empty_mailing_addresses | boolean | true |
When false, excludes properties where mailingfullstreetaddress is empty or missing. |
Accepted input forms: native boolean (true/false), string ("true"/"false"), or numeric (1/0).
Empty addresses with duplicates: false: when empty_mailing_addresses is true (default), properties with an empty or missing mailing address are not collapsed — each is returned as a unique entry.
count field: when duplicates: false, count reflects the actual post-deduplication number of returned properties, not the raw index total.
duplicates | empty_mailing_addresses | Behaviour |
|---|---|---|
true (default) | true (default) | All matching results, no changes. |
true | false | Empty/missing mailing address excluded; no deduplication. |
false | true (default) | Deduplicated by mailing address (largest lotsizeacres kept); empty-mailing properties each returned as a unique entry. |
false | false | Deduplicated by mailing address; empty/missing mailing address excluded entirely. |
{
"duplicates": false,
"filters": {
"fips": {
"operator": "condition",
"value": "39001"
},
"lotsizeacres": {
"operator": "range",
"value": { "min": 5, "max": 50 }
}
}
}
{
"duplicates": false,
"empty_mailing_addresses": false,
"filters": {
"fips": {
"operator": "condition",
"value": "39001"
},
"vacant": {
"operator": "boolean",
"value": true
}
}
}
{
"success": true,
"meta": {
"requests_left": 145,
"message": "Result set is limited to 50000 records. Please narrow your filters."
},
"data": {
"count": 73412,
"properties": []
}
}
When result set exceeds 50000, API returns an empty properties array and recommends narrowing filters. In this case, filter_data_limit is not decremented.
{
"success": true,
"meta": {
"requests_left": 49,
"rejected_filters": [
{
"key": "unknown_filter",
"value": {
"operator": "range",
"value": {
"min": 5,
"max": 10
}
},
"reason": "This filter is invalid. Use GET /filter-data/filters-list to retrieve the latest supported filters and examples."
}
]
},
"data": {
"count": 451,
"properties": [
{
"fips": "39001",
"apn": "048-13-03-018.000",
"situsfullstreetaddress": "19257 STATE ROUTE 136"
}
]
}
}
Full-text search across the property database by parcel number or owner name. Returns a GeoJSON FeatureCollection of matching properties.
https://landportal.com/wp-json/lp-rest-api/v1
All requests must include a JWT token:
Authorization: Bearer <JWT_TOKEN>
search_limit > 0 (decremented only when results are found; resets daily at midnight Eastern Time)| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Search type: parcelnumb or owner. |
query | string | Yes | Search text. Minimum 2 characters. |
fips | string | No | 5-digit FIPS code — narrows results to a specific county. |
state | string | No | 2-letter state code — narrows results to a state. Ignored when fips is provided. |
{
"success": true,
"meta": { "requests_left": 99 },
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [-97.7431, 30.2672] },
"properties": {
"propertyid": "12345678",
"fips": "48453",
"owner": "SMITH JOHN",
"address": "123 Main St, Austin, TX 78701",
"parcelnumb": "1234567890"
}
}
]
}
}
curl -X GET "https://landportal.com/wp-json/lp-rest-api/v1/search?type=owner&query=Smith&state=TX" \
-H "Authorization: Bearer <JWT_TOKEN>"
import requests
url = "https://landportal.com/wp-json/lp-rest-api/v1/search"
headers = {"Authorization": "Bearer <JWT_TOKEN>"}
params = {"type": "owner", "query": "Smith", "state": "TX"}
response = requests.get(url, params=params, headers=headers)
print(response.json())
const response = await fetch(
"https://landportal.com/wp-json/lp-rest-api/v1/search?type=owner&query=Smith&state=TX",
{ headers: { "Authorization": "Bearer <JWT_TOKEN>" } }
);
console.log(await response.json());
| Status | Message | Cause |
|---|---|---|
| 400 | Invalid search type. Allowed: parcelnumb, owner | Unknown type value. |
| 400 | Query must be at least 2 characters | query too short. |
| 403 | Search limit reached | Daily quota exhausted. |
| 403 | API access disabled | API access is disabled for this user. |
| 502 | Search service error | Search service unreachable. |
General integration guidelines that apply across all API endpoints.
Applies to: POST /reports, POST /export, bulk POST /skip-trace (create).
Recommended interval: poll every 3–5 seconds. Stop as soon as status is completed or failed. Polling more frequently does not speed up processing and adds unnecessary load.
Terminal statuses: completed, failed, stopped — no further polling needed once reached.
Endpoints that return lists (e.g. GET /export/tasks) include a pagination object:
"pagination": {
"page": 1,
"per_page": 50,
"total": 17
}
total — total number of items (not pages). Calculate total pages as Math.ceil(total / per_page).
If page > Math.ceil(total / per_page), the response returns an empty tasks array.
Tokens are charged on task creation, before background processing starts. The charge equals the number of unique propertyid values after de-duplication.
Duplicate inputs: duplicate values in fips and propertyid are silently de-duplicated before billing and query execution.
Partial match: if some propertyid values do not exist in the county tables resolved from the given fips, only matching rows appear in the CSV. The task completes successfully with fewer rows than requested. Tokens are not refunded for unmatched IDs.
No match at all: if none of the propertyid values are found, the task transitions to failed with error_message: "The query returned no results". Tokens are not refunded.
Dedicated HTTP rate-limit headers (e.g. X-RateLimit-*) are not returned. Monitor your remaining quota via response fields:
meta.requests_left — filter data, property data, searchmeta.daily_requests_left — comp reports, skip-trace create_singledata.export_tokens_left — export token balance after task creationRetry: transient failures only — network errors, timeouts, 5xx responses.
Do not retry: 4xx errors (validation failures, quota exhausted, auth errors) — they will not resolve on retry.
Strategy: exponential backoff with jitter — e.g. 1s → 2s → 4s, capped at 30s.
Most filter, search, and property-data requests complete in well under a second. Exceptions:
filters.polygon.value now accepts an array of ring strings (["ring1", "ring2"]) in addition to the existing single-string and semicolon-separated formats.;-separated string, array) produce the same Elasticsearch geo_shape query — single ring becomes polygon, multiple rings become multipolygon.FilterGeometryValidator: new parse_rings() method handles format detection; validate_polygon() validates each ring individually.duplicates parameter to POST /filter-data/filter. When false, results are deduplicated by mailingfullstreetaddress, keeping the record with the largest lotsizeacres per unique address.empty_mailing_addresses parameter. When false, properties with an empty or missing mailingfullstreetaddress are excluded from results.duplicates: false and empty_mailing_addresses: true (default), properties without a mailing address are each returned as a unique entry rather than collapsed.duplicates: false, count in the response reflects the post-deduplication result count."true"/"false"), and numeric (1/0) forms.POST /export, GET /export, and GET /export/tasks.fips and propertyid, with server-side normalization.export_tokens_left.GET /export/tasks always returns error_message for each task: string when failed, otherwise false.queued, processing, completed, failed).YYYY-MM-DD (legacy YYYYMMDD remains supported).GET /filter-data/filters-list to use YYYY-MM-DD.nulls in multiple input forms: boolean (true/false), string ("true"/"false", "yes"/"no"), and numeric (1/0, including numeric strings).nulls: true includes records with missing/null date values; nulls: false returns only records matching the date condition.percentage_of_land_with_flat_slope_0_05, sum_up_to_5, sum_up_to_10, sum_up_to_15.value.min without value.max).meta.requests_left.count > 50000.GET /property-data supports lookup by lat + lng when propertyid + fips are not provided.GET /property-data returns combined remaining quota in meta.requests_left (daily single-property limit + export tokens, when available).GET /property-data now uses export tokens after daily quota is exhausted (when available).create_single: all fields are now optional. The address field accepts any address associated with the consumer.create_single: response now includes line_type and dnc_types array per phone number.GET /reports endpoint for fetching existing comp reports.search_limit daily quota for GET /search.single_property_limit enforcement in GET /property-data.requests_left or daily_requests_left).create_single skip-trace method with Versium + TCPA Litigator scrub.finish now sends a webhook callback to the URL set in the user profile.processing_time, average_hit_rate, credit_consumed, failed_rows.Main Search Index field).GET /search endpoint.GET /property-data.pause / continue skip-trace methods.GET /property-data, POST /reports, POST /skip-trace (create, get, stop, update, delete, finish).