Developer Docs
Download .md file (Feed to AI for context)

Skip Tracing API Documentation

Build on Tracerfy's skip tracing platform. Secure, scalable REST API designed for high-volume property owner contact data retrieval workflows.

Base URL
https://tracerfy.com/v1/api/
Auth
Authorization: Bearer <TOKEN>
GET

Fetch all Queue

/v1/api/queues/
Description: Returns the authenticated user's queues as a JSON array, ordered by most recent first. Each queue represents a trace job created via API or the app. While a queue is pending, rows_uploaded and credits_deducted are hidden; when complete, download_url is populated with a CSV link.

Up to 100 queues per page. Pass ?page=N to walk back through history. Pagination metadata is in the response headers β€” X-Total-Count for the total, and Link for navigation:

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
page
query
integer
No
Page number to return. Default: 1. 100 queues per page.

Example Request

# Default β€” page 1, latest 100 queues
curl -i -X GET 'https://tracerfy.com/v1/api/queues/' -H 'Authorization: Bearer '

# Walk back through history
curl -i -X GET 'https://tracerfy.com/v1/api/queues/?page=2' -H 'Authorization: Bearer '

Example Response 200

[
  {
    "id": 124,
    "created_at": "2025-01-02T09:30:00Z",
    "pending": true,
    "download_url": null,
    "rows_uploaded": 1800,
    "credits_deducted": 0,
    "queue_type": "api",
    "trace_type": "normal",
    "credits_per_lead": 1
  },
  {
    "id": 123,
    "created_at": "2025-01-01T12:00:00Z",
    "pending": false,
    "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/9a584124-77c2-4612-b8e9-f9efe6fbdc3d.csv",
    "rows_uploaded": 2500,
    "credits_deducted": 2500,
    "queue_type": "api",
    "trace_type": "normal",
    "credits_per_lead": 1
  }
]
GET

Fetch Single Queue

/v1/api/queue/:id
Description: Returns the property records associated with a queue's posted addresses. Object-level permission enforced: only the queue owner can access. Null contact fields are normalized to empty strings in the response.

Response varies based on trace_type:
β€’ Normal Trace (trace_type='normal'): Returns basic property contact data (phones and emails)
β€’ Advanced Trace (trace_type='advanced'): Finds the property owner and returns their contact data (name, phones, emails and mailing address)
β€’ Custom Trace (trace_type='custom'): Returns basic property contact data (phones, emails, mailing address)

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
:id
path
integer
Yes
Queue ID

Example Request

curl -X GET 'https://tracerfy.com/v1/api/queue/123' -H 'Authorization: Bearer '

Example Response 200

// Normal Trace Response (trace_type='normal')
[
  {
    "address": "123 Main St",
    "city": "Austin",
    "state": "TX",
    "mail_address": "PO Box 111",
    "mail_city": "Austin",
    "mail_state": "TX",
    "first_name": "Jane",
    "last_name": "Doe",
    "primary_phone": "5125550100",
    "primary_phone_type": "Mobile",
    "email_1": "[email protected]",
    "email_2": "",
    "email_3": "",
    "email_4": "",
    "email_5": "",
    "mobile_1": "5125550100",
    "mobile_2": "",
    "mobile_3": "",
    "mobile_4": "",
    "mobile_5": "",
    "landline_1": "",
    "landline_2": "",
    "landline_3": ""
  }
]
GET

Analytics

/v1/api/analytics/
Description: Aggregated summary for your account: total_queues, properties_traced (sum of posted addresses per queue), queues_pending, queues_completed, and current credit balance.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Example Request

curl -X GET 'https://tracerfy.com/v1/api/analytics/' -H 'Authorization: Bearer '

Example Response 200

{
  "total_queues": 12,
  "properties_traced": 18350,
  "queues_pending": 2,
  "queues_completed": 10,
  "balance": 940
}
POST

Batch Trace

/v1/api/trace/
Description: Asynchronous batch endpoint for processing multiple addresses at once via CSV or JSON. Specify trace_type='normal' (1 credit/lead) or 'advanced' (2 credits/lead). Cleans and de-duplicates rows, then enqueues processing in the background. If credits are insufficient the request is rejected. Returns a queue_id immediately along with estimated_wait_seconds (estimated processing time in seconds); results are delivered via download_url when complete. For single-address instant lookups, use the Instant Trace Lookup endpoint instead.

⚠️ API Usage Policy: Do not abuse API POST calls. Accounts found to be abusing the API will be put on hold. Maximum rate limit is 10 POST trace requests per 5-minute window. Please use the API responsibly and in accordance with our Terms of Service - API Rate Limits & Abuse Policy.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = multipart/form-data or application/json

Parameters

Name
In
Type
Required
Description
address_column
body
string
Yes
Column for property address
city_column
body
string
Yes
Column for property city
state_column
body
string
Yes
Column for property state
zip_column
body
string
No
Property ZIP (optional β€” for advanced traces, we return this from our data if not provided)
first_name_column
body
string
Yes
Owner first name (optional for advanced traces β€” we identify the owner for you)
last_name_column
body
string
Yes
Owner last name (optional for advanced traces β€” we identify the owner for you)
mail_address_column
body
string
Yes
Mailing address (optional for advanced traces β€” we return this from our data)
mail_city_column
body
string
Yes
Mailing city (optional for advanced traces β€” we return this from our data)
mail_state_column
body
string
Yes
Mailing state (optional for advanced traces β€” we return this from our data)
mailing_zip_column
body
string
No
Mailing ZIP (optional β€” for advanced traces, we return this from our data if not provided)
trace_type
body
string
No
Trace type: 'normal' (1 credit/lead) or 'advanced' (2 credits/lead). Defaults to 'normal'. For advanced traces, only address_column, city_column, and state_column are required β€” all other fields are optional as we identify the owner and return their full contact and mailing info.
csv_file
form-data
file
Yes
CSV file of records
json_data
body
string
No
Raw JSON array of records (alternative to csv_file)

Example Request

curl -X POST 'https://tracerfy.com/v1/api/trace/' \
  -H 'Authorization: Bearer ' \
  -F 'csv_file=@/path/to/records.csv' \
  -F 'address_column=address' \
  -F 'city_column=city' \
  -F 'state_column=state' \
  -F 'zip_column=zip' \
  -F 'first_name_column=first_name' \
  -F 'last_name_column=last_name' \
  -F 'mail_address_column=mail_address' \
  -F 'mail_city_column=mail_city' \
  -F 'mail_state_column=mail_state' \
  -F 'mailing_zip_column=mailing_zip' \
  -F 'trace_type=normal'

Example Response 200

{
  "message": "Queue created",
  "queue_id": 456,
  "status": "pending",
  "created_at": "2025-01-02T10:15:00Z",
  "rows_uploaded": 100,
  "trace_type": "normal",
  "credits_per_lead": 1,
  "estimated_wait_seconds": 30
}
POST

Instant Trace Lookup (Synchronous)

/v1/api/trace/lookup/
Description: Synchronous single-address skip trace. Returns responses immediately as JSON β€” no queue and no CSV. Ideal for one-off lookups or integrating skip trace data into your own UI at scale.

5 credits per hit, 0 credits on miss. Rate limited to 500 RPM per user.

Two lookup modes:
β€’ find_owner: true (default) β€” send only address/city/state, returns the property owner(s) and their contact info
β€’ find_owner: false β€” include first_name + last_name to search for a specific person at the address

Response includes per person: name, age, DOB, deceased flag, property owner flag, litigator flag, mailing address, all phones (with DNC status, carrier, type, rank), and all emails.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
address
body
string
Yes
Property street address
city
body
string
Yes
Property city
state
body
string
Yes
Property state (2-letter abbreviation)
zip
body
string
No
Property ZIP code. Optional but strongly recommended β€” without it, results may match a different property at a similar address in the same city.
find_owner
body
boolean
No
true (default) β€” find property owner, no name needed. false β€” find a specific person at the address, requires first_name + last_name.
first_name
body
string
No
Person's first name. Required when find_owner is false.
last_name
body
string
No
Person's last name. Required when find_owner is false.

Example Request

# Owner lookup (find property owner)
curl -X POST 'https://tracerfy.com/v1/api/trace/lookup/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"address": "123 Main St", "city": "Austin", "state": "TX", "zip": "78701", "find_owner": true}'

# Person lookup (find specific person at address)
curl -X POST 'https://tracerfy.com/v1/api/trace/lookup/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"address": "123 Main St", "city": "Austin", "state": "TX", "zip": "78701", "find_owner": false, "first_name": "Jane", "last_name": "Doe"}'

Example Response 200

// Owner lookup hit (find_owner: true) β€” 5 credits deducted
{
  "address": "123 Main St",
  "city": "Austin",
  "state": "TX",
  "zip": "78701",
  "find_owner": true,
  "hit": true,
  "persons_count": 1,
  "credits_deducted": 5,
  "persons": [
    {
      "first_name": "Jane",
      "last_name": "Doe",
      "full_name": "Jane Doe",
      "dob": "1985-03-22",
      "age": "41",
      "deceased": false,
      "property_owner": true,
      "litigator": false,
      "mailing_address": {
        "street": "PO Box 111",
        "city": "Austin",
        "state": "TX",
        "zip": "78702"
      },
      "phones": [
        {
          "number": "5125550100",
          "type": "Mobile",
          "dnc": false,
          "carrier": "T-MOBILE USA INC.",
          "rank": 1
        },
        {
          "number": "5125550200",
          "type": "Landline",
          "dnc": true,
          "carrier": "AT&T TEXAS",
          "rank": 2
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        }
      ]
    }
  ]
}

// Person lookup hit (find_owner: false) β€” 5 credits deducted
{
  "address": "123 Main St",
  "city": "Austin",
  "state": "TX",
  "zip": "78701",
  "find_owner": false,
  "hit": true,
  "persons_count": 1,
  "credits_deducted": 5,
  "persons": [
    {
      "first_name": "John",
      "last_name": "Smith",
      "full_name": "John Smith",
      "dob": "1978-11-03",
      "age": "47",
      "deceased": false,
      "property_owner": false,
      "litigator": false,
      "mailing_address": {
        "street": "456 Oak Ave",
        "city": "Dallas",
        "state": "TX",
        "zip": "75201"
      },
      "phones": [
        {
          "number": "2145550300",
          "type": "Mobile",
          "dnc": false,
          "carrier": "VERIZON WIRELESS",
          "rank": 1
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        }
      ]
    }
  ]
}

// Miss β€” no results found, 0 credits deducted
{
  "address": "999 Nowhere Blvd",
  "city": "Austin",
  "state": "TX",
  "zip": "78701",
  "find_owner": true,
  "hit": false,
  "persons_count": 0,
  "credits_deducted": 0,
  "persons": []
}
POST

APN Batch Trace

/v1/api/trace/parcel/
Description: Submit a batch of parcel IDs (APNs) for skip tracing. Each parcel is looked up to find the property owner's contact information β€” name, mailing address, phones with DNC flags and carrier, and emails.

5 credits per hit, 0 on miss. Rows with no match still appear in the CSV with empty contact columns.

Results are delivered asynchronously via a CSV download URL. Poll the queue endpoint GET /v1/api/trace/parcel/queue/:id for status, or set a webhook URL in your account to get notified on completion.

APN format: the # prefix is optional and will be stripped automatically. Parcel IDs are formatted internally to match the standard APN format for each county.

Rate limit: 10 batch submissions per 5 minutes.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = multipart/form-data

Parameters

Name
In
Type
Required
Description
csv_file
form-data
file
Yes
CSV file with parcel ID, county, and state columns.
parcel_id_column
body
string
Yes
Name of the column containing parcel IDs.
county_column
body
string
Yes
Name of the column containing county names.
state_column
body
string
Yes
Name of the column containing state abbreviations (e.g. FL, TX).

Example Request

curl -X POST 'https://tracerfy.com/v1/api/trace/parcel/' \
  -H 'Authorization: Bearer ' \
  -F '[email protected]' \
  -F 'parcel_id_column=parcel_id' \
  -F 'county_column=county' \
  -F 'state_column=state'

Example Response 200

{
  "message": "Parcel trace started",
  "parcel_queue_id": 42,
  "created_at": "2026-04-07T12:00:00Z",
  "status": "pending",
  "rows_uploaded": 500,
  "credits_per_parcel": 5
}

Missing or invalid columns

{
  "error": "Column 'parcel_id' not found in the uploaded CSV."
}

Insufficient credits

{
  "error": "Insufficient credits for parcel trace."
}
POST

APN Instant Lookup (Synchronous)

/v1/api/trace/parcel/lookup/
Description: Synchronous single-parcel skip trace. Returns owner contact info immediately as JSON β€” no queue, no CSV, no polling. Use this when you have one APN and want instant results.

5 credits per hit, 0 on miss.

The response includes every field the batch CSV delivers: owner name, property address, mailing address, all phones with DNC flag and carrier, emails, plus property_owner, deceased, litigator, and age.

APN format: the # prefix is optional.

Rate limit: 500 requests per minute per user.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
parcel_id
body
string
Yes
The parcel ID (APN). The '#' prefix is optional and will be stripped automatically.
county
body
string
Yes
County name (e.g. 'Palm Beach').
state
body
string
Yes
State abbreviation (e.g. 'FL').

Example Request

curl -X POST 'https://tracerfy.com/v1/api/trace/parcel/lookup/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"parcel_id": "#00424109000007550", "county": "Palm Beach", "state": "FL"}'

Example Response 200

// Hit β€” 5 credits deducted
{
  "parcel_id": "#00424109000007550",
  "county": "Palm Beach",
  "state": "FL",
  "hit": true,
  "persons_count": 1,
  "credits_deducted": 5,
  "persons": [
    {
      "first_name": "John",
      "last_name": "Smith",
      "full_name": "John Smith",
      "dob": "1975-03-15",
      "age": 51,
      "deceased": false,
      "property_owner": true,
      "litigator": false,
      "mailing_address": {
        "street": "456 Oak Ave",
        "city": "West Palm Beach",
        "state": "FL",
        "zip": "33401"
      },
      "phones": [
        {
          "number": "5615550100",
          "type": "Mobile",
          "dnc": false,
          "carrier": "T-MOBILE USA INC.",
          "rank": 1
        },
        {
          "number": "5615550200",
          "type": "Landline",
          "dnc": true,
          "carrier": "BELLSOUTH TELECOMM INC",
          "rank": 2
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        },
        {
          "email": "[email protected]",
          "rank": 2
        }
      ]
    }
  ]
}

// Miss β€” 0 credits
{
  "parcel_id": "#00404033000001190",
  "county": "Palm Beach",
  "state": "FL",
  "hit": false,
  "persons_count": 0,
  "credits_deducted": 0,
  "persons": []
}

Insufficient credits

{
  "error": "Insufficient credits. Parcel trace requires 5 credits per lookup."
}

Upstream temporarily unavailable

{
  "error": "Skip trace service temporarily unavailable. Please try again."
}
POST

Trace Webhooks

Account.webhook_url
Description: When a batch skip trace queue completes, Tracerfy POSTs the result to the webhook URL configured in your account profile. This is per-user and dynamic; no registration endpoint is required.

Three payload shapes can arrive at this endpoint, depending on which trace finished:
β€’ Normal skip trace β€” distinguished by trace_type: "normal" and credits_per_lead: 1.
β€’ Advanced skip trace β€” distinguished by trace_type: "advanced" and credits_per_lead: 2.
β€’ APN / parcel trace β€” distinguished by type: "parcel_trace" and the parcel_queue_id field. Different shape (no trace_type); uses credits_per_parcel instead.

The Enhanced (deprecated) and Custom trace types follow the same shape as Normal / Advanced; only the trace_type string and credits_per_lead value differ.

Headers

  • Content-Type = application/json

Example Request

Tracerfy sends one of the JSON shapes below to your Account.webhook_url when a trace completes.

Example Response 200

// Normal skip trace completed β€” 1 credit per hit
{
  "id": 365,
  "created_at": "2025-07-13T18:55:02.962332Z",
  "pending": false,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/9a584124-77c2-4612-b8e9-f9efe6fbdc3d.csv",
  "rows_uploaded": 12,
  "credits_deducted": 12,
  "queue_type": "api",
  "trace_type": "normal",
  "credits_per_lead": 1
}

// Advanced skip trace completed β€” 2 credits per hit
{
  "id": 366,
  "created_at": "2025-07-13T19:02:18.114402Z",
  "pending": false,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/2b7e9a44-3812-4ae1-8c0f-1d7e92a4f111.csv",
  "rows_uploaded": 12,
  "credits_deducted": 24,
  "queue_type": "api",
  "trace_type": "advanced",
  "credits_per_lead": 2
}

// APN / parcel trace completed β€” 5 credits per hit, different payload shape
{
  "type": "parcel_trace",
  "event": "parcel_trace.completed",
  "parcel_queue_id": 42,
  "status": "completed",
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/parcel-trace-42.csv",
  "rows_uploaded": 500,
  "rows_hit": 423,
  "credits_deducted": 2115,
  "credits_per_parcel": 5
}
POST

Start DNC Scrub

/v1/api/dnc/scrub/
Description: Submit a phone list for DNC (Do Not Call) scrubbing. Upload a CSV with one or more phone columns, or pass a JSON array of phone numbers directly. Each phone is checked against Federal DNC, State DNC, DMA, and TCPA Litigator databases. 1 credit per phone checked.

Input options (pick one):
β€’ CSV with single column: csv_file + phone_column (string)
β€’ CSV with multiple columns: csv_file + phone_columns (array) β€” phones are merged & deduplicated
β€’ JSON phone list: phones array via application/json

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = multipart/form-data or application/json

Parameters

Name
In
Type
Required
Description
csv_file
form-data
file
Yes
CSV file containing phone numbers. Required for Options 1 & 2. Do not send with phones.
phone_column
body
string
Yes
Single column name containing phone numbers (Option 1). Internally normalized to phone_columns. Mutually exclusive with phone_columns.
phone_columns
body
array[string]
Yes
List of column names containing phone numbers (Option 2). Phones are merged & deduplicated. When multiple columns are used, labels are prefixed with the column name, e.g. '(Phone_1) John Doe'. Mutually exclusive with phone_column.
label_column
body
string
No
Single column to label each phone (e.g., name). Internally normalized to label_columns. Mutually exclusive with label_columns.
label_columns
body
array[string]
No
List of columns to combine as a label for each phone (e.g., ["address", "city", "state"]). Values are joined with commas. When using multiple phone_columns, labels are also prefixed with the column name.
phones
body
array[string]
Yes
Direct list of phone numbers via JSON body (Option 3). Do not send with csv_file.

Example Request

# Option 1: CSV with a single phone column
curl -X POST 'https://tracerfy.com/v1/api/dnc/scrub/' \
  -H 'Authorization: Bearer ' \
  -F 'csv_file=@/path/to/phones.csv' \
  -F 'phone_column=Phone' \
  -F 'label_column=Name'

# Option 1b: CSV with multiple label columns
curl -X POST 'https://tracerfy.com/v1/api/dnc/scrub/' \
  -H 'Authorization: Bearer ' \
  -F 'csv_file=@/path/to/phones.csv' \
  -F 'phone_column=Phone' \
  -F 'label_columns=["Address", "City", "State"]'

# Option 2: CSV with multiple phone columns
curl -X POST 'https://tracerfy.com/v1/api/dnc/scrub/' \
  -H 'Authorization: Bearer ' \
  -F 'csv_file=@/path/to/phones.csv' \
  -F 'phone_columns=["Phone_1", "Phone_2"]' \
  -F 'label_column=Name'

# Option 3: JSON phone list (no CSV)
curl -X POST 'https://tracerfy.com/v1/api/dnc/scrub/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"phones": ["5125550100", "5125550101", "5125550102"]}'

Example Response 200

{
  "message": "DNC scrub started",
  "dnc_queue_id": 5,
  "created_at": "2025-01-15T09:30:00Z",
  "status": "pending",
  "phones_to_check": 150,
  "credits_per_phone": 1
}
POST

DNC Scrub from Trace

/v1/api/dnc/scrub-from-queue/
Description: Extract phone numbers from a completed trace queue from your skip tracing results and submit them for DNC scrubbing. Optionally specify which phone columns to include. Phones are deduplicated across all selected columns. 1 credit per phone checked.

Valid phone_columns: primary_phone, mobile_1, mobile_2, mobile_3, mobile_4, mobile_5, landline_1, landline_2, landline_3
If phone_columns is omitted, all 9 phone fields are included by default.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
queue_id
body
integer
Yes
ID of a completed trace queue to extract phones from.
phone_columns
body
array[string]
No
List of phone field names to include. Defaults to all 9 phone fields.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/dnc/scrub-from-queue/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"queue_id": 37360, "phone_columns": ["primary_phone", "mobile_1", "mobile_2"]}'

Example Response 200

{
  "message": "DNC scrub started",
  "dnc_queue_id": 8,
  "created_at": "2025-01-15T10:00:00Z",
  "source_queue_id": 37360,
  "status": "pending",
  "phones_to_check": 23,
  "phone_columns_used": [
    "primary_phone",
    "mobile_1",
    "mobile_2"
  ],
  "credits_per_phone": 1
}
GET

Fetch DNC Queue

/v1/api/dnc/queue/:id
Description: Retrieve the status and results of a DNC scrub job. When complete, two download URLs are provided: download_url (all phones with DNC flags) and clean_download_url (only phones with no DNC flags). CSV columns: phone, label, national_dnc, state_dnc, dma, litigator, phone_type, is_clean.

Note: While the queue is still pending, the fields phones_checked, phones_clean, and credits_deducted are omitted from the response. They appear once the scrub completes.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
:id
path
integer
Yes
DNC Queue ID

Example Request

curl -X GET 'https://tracerfy.com/v1/api/dnc/queue/5' -H 'Authorization: Bearer '

Example Response 200

{
  "id": 5,
  "created_at": "2025-01-15T09:30:00Z",
  "pending": false,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/full-results.csv",
  "clean_download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/clean-results.csv",
  "rows_uploaded": 150,
  "phones_checked": 150,
  "phones_clean": 112,
  "credits_deducted": 150,
  "source_type": "upload"
}
POST

DNC Instant Lookup (Synchronous)

/v1/api/dnc/lookup/
Description: Synchronous single-phone DNC check. Send one phone number, get back Federal DNC, State DNC, DMA, and TCPA Litigator flags immediately. No queue, no CSV, no waiting.

Billing: 5 credits per lookup.

Use this when: you need to check a single number before dialing or as part of a real-time CRM workflow. For bulk scrubbing (100+ phones), use POST /v1/api/dnc/scrub/ instead.

Response fields:
- national_dnc β€” on the Federal Do Not Call Registry
- state_dnc β€” on a State DNC list
- dma β€” on the Direct Marketing Association list
- litigator β€” known TCPA litigator
- phone_type β€” Mobile or Landline
- is_clean β€” true only if no flags are set

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
phone
body
string
Yes
10-digit US phone number. Formatting is stripped automatically (dashes, spaces, parentheses, leading 1).

Example Request

curl -X POST 'https://tracerfy.com/v1/api/dnc/lookup/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"phone": "4805551234"}'

Example Response 200

// Flagged β€” not clean
{
  "phone": "4805551234",
  "hit": true,
  "national_dnc": true,
  "state_dnc": false,
  "dma": false,
  "litigator": false,
  "phone_type": "Mobile",
  "is_clean": false,
  "credits_deducted": 5
}

// Clean β€” safe to proceed
{
  "phone": "6025559876",
  "hit": true,
  "national_dnc": false,
  "state_dnc": false,
  "dma": false,
  "litigator": false,
  "phone_type": "Landline",
  "is_clean": true,
  "credits_deducted": 5
}

Invalid phone

{
  "error": "Invalid phone number. Must be a 10-digit US number."
}

Insufficient credits

{
  "error": "Insufficient credits. DNC lookup requires 5 credits. You have 0 credits."
}
POST

DNC Webhooks

Account.webhook_url
Description: When a DNC scrub completes, Tracerfy POSTs the result to the webhook URL configured in your account profile. The payload includes a type: "dnc_scrub" field to distinguish it from trace webhooks, plus DNC-specific fields like clean_download_url, phones_checked, and phones_clean.

Headers

  • Content-Type = application/json

Example Request

Tracerfy sends this JSON to your Account.webhook_url when a DNC scrub completes.

Example Response 200

{
  "id": 5,
  "type": "dnc_scrub",
  "created_at": "2025-01-15T09:30:00Z",
  "pending": false,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/full-results.csv",
  "clean_download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/clean-results.csv",
  "rows_uploaded": 150,
  "phones_checked": 150,
  "phones_clean": 112,
  "credits_deducted": 150,
  "source_type": "upload"
}
GET

List Filters

/v1/api/lead-builder/filters/
Description: Returns every Lead Builder preset strategy with its human-readable label, description, and the exact filters the preset applies. Use this to enumerate available filters at runtime instead of hard-coding the list in your client. Response is static enough to cache locally for ~1 hour.

For each strategy, default_filters shows the filters that the preset lays down β€” anything you send in filter_overrides on /preview/ or /execute/ will merge on top. This lets you see exactly what 'tired_landlord' does before you use it.

For the complete list of individual filter keys you can use in filter_overrides, see the Filter Reference below.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Example Request

curl 'https://tracerfy.com/v1/api/lead-builder/filters/' \
  -H 'Authorization: Bearer '

Example Response 200

{
  "strategies": [
    {
      "key": "pre_foreclosure_motivated",
      "label": "Pre-Foreclosure",
      "description": "Active pre-foreclosure filings in the last 6 months.",
      "default_filters": {
        "pre_foreclosure": true,
        "search_range": "6_MONTH"
      }
    },
    {
      "key": "probate_inherited",
      "label": "Probate / Inherited",
      "description": "Inherited properties β€” high-intent probate leads.",
      "default_filters": {
        "inherited": true
      }
    },
    {
      "key": "vacant",
      "label": "Vacant Homes",
      "description": "Vacant properties β€” no one residing at the address.",
      "default_filters": {
        "vacant": true
      }
    },
    {
      "key": "high_equity_absentee",
      "label": "High Equity Absentee",
      "description": "Absentee owners with the high-equity flag β€” motivated seller candidates.",
      "default_filters": {
        "absentee_owner": true,
        "high_equity": true
      }
    },
    {
      "key": "tired_landlord",
      "label": "Tired Landlord",
      "description": "Absentee owners who have held 7+ years and own 2+ properties.",
      "default_filters": {
        "absentee_owner": true,
        "years_owned_min": 7,
        "properties_owned_min": 2
      }
    },
    {
      "key": "reo_bank_owned",
      "label": "REO / Bank-Owned",
      "description": "Bank-owned (REO) properties β€” post-foreclosure distressed inventory.",
      "default_filters": {
        "reo": true
      }
    },
    {
      "key": "cash_buyer_investor",
      "label": "Cash Buyer",
      "description": "Recent cash buyers β€” wholesaling dispo list candidates.",
      "default_filters": {
        "cash_buyer": true
      }
    },
    {
      "key": "free_and_clear",
      "label": "Free & Clear",
      "description": "Properties owned outright with no active mortgage.",
      "default_filters": {
        "free_clear": true
      }
    },
    {
      "key": "auction_property",
      "label": "Auction Properties",
      "description": "Properties scheduled for auction β€” distressed seller opportunity.",
      "default_filters": {
        "auction": true
      }
    },
    {
      "key": "judgment_lien",
      "label": "Judgment / Lien",
      "description": "Properties with court judgments β€” financially distressed owners.",
      "default_filters": {
        "judgment": true
      }
    },
    {
      "key": "owner_deceased",
      "label": "Owner Deceased",
      "description": "Properties where the owner of record is deceased β€” estate sale candidates.",
      "default_filters": {
        "death": true
      }
    },
    {
      "key": "active_flipper",
      "label": "Active Flipper",
      "description": "Investors who bought 2+ properties in the last 12 months.",
      "default_filters": {
        "investor_buyer": true,
        "portfolio_purchased_last12_min": 2
      }
    },
    {
      "key": "expired_mls",
      "label": "Expired MLS Listings",
      "description": "Properties that were listed for sale but failed to sell β€” motivated seller candidates for agents.",
      "default_filters": {
        "mls_cancelled": true
      }
    },
    {
      "key": "recent_homeowner",
      "label": "Recent Homeowner",
      "description": "Bought in the last 6 months β€” home improvement, refi, warranty cross-sell.",
      "default_filters": {
        "last_sale_date_min": "2025-11-06",
        "absentee_owner": false
      }
    },
    {
      "key": "long_term_owner_listing_opportunity",
      "label": "Long-Term Owner",
      "description": "Owner-occupied 10+ years β€” potential listing leads.",
      "default_filters": {
        "years_owned_min": 10,
        "absentee_owner": false
      }
    },
    {
      "key": "high_equity_refi_candidate",
      "label": "High Equity Refi",
      "description": "Owner-occupied with the high-equity flag β€” refinance leads.",
      "default_filters": {
        "absentee_owner": false,
        "high_equity": true
      }
    },
    {
      "key": "solar_owner_occupied_high_value",
      "label": "Solar (Owner-Occupied, High Value)",
      "description": "SFRs built before 2015, owner-occupied, high equity, $300k+ value.",
      "default_filters": {
        "property_type": "SFR",
        "absentee_owner": false,
        "value_min": 300000,
        "year_built_max": 2015,
        "high_equity": true
      }
    },
    {
      "key": "roofing_older_home_high_equity",
      "label": "Roofing (Older Home, High Equity)",
      "description": "SFRs built before 2005, owner-occupied, high equity.",
      "default_filters": {
        "property_type": "SFR",
        "year_built_max": 2005,
        "high_equity": true,
        "absentee_owner": false
      }
    },
    {
      "key": "hvac_older_home_owner_occupied",
      "label": "HVAC (Older Home, Owner-Occupied)",
      "description": "SFRs built before 2000, owner-occupied. Aging HVAC replacement market.",
      "default_filters": {
        "property_type": "SFR",
        "year_built_max": 2000,
        "absentee_owner": false
      }
    },
    {
      "key": "custom",
      "label": "Custom",
      "description": "Blank slate β€” configure every filter manually or via AI prompt.",
      "default_filters": {}
    }
  ]
}
POST

Preview Lead List

/v1/api/lead-builder/preview/
Description: Preview a lead list before charging. Returns the total match count, the capped count (the lower of total_matches and your requested_count), and the maximum credit cost. Preview calls do not charge credits.

Use this to iterate on filters and geography before committing β€” safe to call repeatedly. Rate limited to 500 calls per hour per account.

About max_credit_cost: 5 credits per row in the delivered CSV. The value is the ceiling β€” if fewer properties match than requested_count, capped_count drops and the charge drops with it.

Filters: see List Filters for preset strategies, or use 'custom' and supply individual filters via filter_overrides. Full key reference at Filter Reference.

Geography modes: zips, city, counties, states, radius. See the shape examples under the geography param below.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
strategy
body
string
No
Strategy key from /filters/. Defaults to 'custom'. Supports comma-separated multi-select (e.g. 'pre_foreclosure_motivated,probate_inherited,vacant') to combine multiple lead types with OR logic.
geography
body
object
Yes
Geography dict with a required mode field. Shapes:
β€’ {"mode": "zips", "zip_codes": ["85001","85004"]}
β€’ {"mode": "city", "cities": ["Phoenix"], "states": ["AZ"]}
β€’ {"mode": "counties", "counties": ["Maricopa"], "states": ["AZ"]}
β€’ {"mode": "states", "states": ["AZ","TX"]}
β€’ {"mode": "radius", "latitude": 33.45, "longitude": -112.07, "radius": 5} (miles)
filter_overrides
body
object
No
Filters merged on top of the strategy defaults. See Filter Reference for every accepted key.
requested_count
body
integer
Yes
Maximum rows you'd pay for. 1-25000. capped_count in the response = min(total_matches, requested_count).
include_pins
body
boolean
No
When true, the response also includes up to 500 {latitude, longitude} pins for map rendering. Defaults to false for API callers who don't need them.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/lead-builder/preview/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{
    "strategy": "high_equity_absentee",
    "geography": {"mode": "city", "cities": ["Phoenix"], "states": ["AZ"]},
    "filter_overrides": {"year_built_max": 2015},
    "requested_count": 500
  }'

Example Response 200

{
  "count": 2340,
  "capped_count": 500,
  "requested_count": 500,
  "max_credit_cost": 2500,
  "max_credit_cost_usd": 50.0,
  "strategy": "high_equity_absentee",
  "strategy_label": "High Equity Absentee",
  "filters_applied": {
    "absentee_owner": true,
    "high_equity": true,
    "state": "AZ",
    "city": "Phoenix"
  }
}

Unknown strategy

{
  "strategy": [
    "Unknown strategy 'not_a_real_strategy'. Valid options: call GET /v1/api/lead-builder/strategies/"
  ]
}

Rate limit (120/hr)

{
  "detail": "Preview rate limit exceeded."
}

Upstream temporarily unavailable

{
  "error": "Lead preview service temporarily unavailable. Please try again."
}
POST

Execute Lead Build

/v1/api/lead-builder/execute/
Description: Create a lead list and dispatch the build task. This is the charged path β€” 5 credits per delivered row. Rate limited to 10 executes per hour, 50 per day, per user.

Returns a 202 with the new id and a poll_url. The build runs asynchronously and typically takes 1-5 minutes depending on requested_count. Poll the status endpoint until completion, or configure your account webhook to get notified automatically.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
strategy
body
string
No
Same as /preview/. Defaults to 'custom'.
geography
body
object
Yes
Same shape as /preview/.
filter_overrides
body
object
No
Same shape as /preview/.
requested_count
body
integer
Yes
1-25000. Billed at 5 credits per delivered row, capped here.
name
body
string
No
Optional label shown in /lead-lists/ and the status response.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/lead-builder/execute/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{
    "strategy": "high_equity_absentee",
    "geography": {"mode": "city", "cities": ["Phoenix"], "states": ["AZ"]},
    "filter_overrides": {"year_built_max": 2015},
    "requested_count": 500,
    "name": "Phoenix Q2 Prospects"
  }'

Example Response 202

{
  "id": 42,
  "status": "pending",
  "progress_stage": "",
  "created_at": "2026-04-11T18:23:00Z",
  "requested_count": 500,
  "max_credit_cost": 2500,
  "poll_url": "/v1/api/lead-builder/42/"
}

No matches β€” widen your filters

{
  "error": "No properties match this filter set. Widen your filters and try again.",
  "matches": 0
}

Insufficient credits

{
  "error": "Insufficient credits. This lead list requires up to 2500 credits (5 per row \u00d7 500 rows). You have 100 credits."
}

Unpaid invoice β€” account suspended

{
  "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact [email protected] to resolve outstanding payments."
}
GET

Check Build Status

/v1/api/lead-builder/<id>/
Description: Poll a lead list for completion status. Returns the current stage, progress percent, and the CSV download_url once the build finishes.

Stages: fetching_properties β†’ skip_tracing β†’ generating_csv β†’ (empty when complete).

Ownership is enforced β€” you can only poll lead lists your account created. Unknown IDs return 404 (same as cross-user access attempts, to prevent ID enumeration).

Polling cadence: poll every 2-5 seconds and back off as the stage advances, or skip polling entirely by configuring your account webhook.

The CSV: download_url is a time-limited signed URL (valid ~1 hour).

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
id
path
integer
Yes
The LeadList id returned from the execute endpoint.

Example Request

curl 'https://tracerfy.com/v1/api/lead-builder/42/' \
  -H 'Authorization: Bearer '

Example Response 200

// Complete β€” download_url ready
{
  "id": 42,
  "name": "Phoenix Q2 Prospects",
  "strategy": "high_equity_absentee",
  "strategy_label": "High Equity Absentee",
  "source": "api",
  "status": "complete",
  "progress_stage": "",
  "progress_percent": 100,
  "requested_count": 500,
  "actual_count": 487,
  "credits_deducted": 2435,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/lead_list_42_a1b2c3d4.csv",
  "error_message": "",
  "created_at": "2026-04-11T18:23:00Z",
  "completed_at": "2026-04-11T18:37:42Z",
  "poll_url": "/v1/api/lead-builder/42/"
}

// Pending β€” still building
{
  "id": 42,
  "name": "Phoenix Q2 Prospects",
  "strategy": "high_equity_absentee",
  "strategy_label": "High Equity Absentee",
  "source": "api",
  "status": "pending",
  "progress_stage": "skip_tracing",
  "progress_percent": 47,
  "requested_count": 500,
  "actual_count": null,
  "credits_deducted": 0,
  "download_url": "",
  "error_message": "",
  "created_at": "2026-04-11T18:23:00Z",
  "completed_at": null,
  "poll_url": "/v1/api/lead-builder/42/"
}
GET

Lead List Rows (JSON)

/v1/api/lead-builder/<id>/rows/
Description: Paginated JSON access to the rows in a completed lead list. Same data as the CSV download, delivered as a JSON array β€” no file parsing needed.

Use this when: you want to consume lead data programmatically without downloading and parsing a CSV. Perfect for CRM integrations, webhooks, or piping rows directly into your application.

No extra charge: the data was already paid for on /execute/. This endpoint is a free read.

Pagination: defaults to 100 rows per page (max 500). Use page and per_page query params. Returns 409 if the list is still processing.

Propensity scores included on every row. Each row carries 5 independent propensity scores so the same lead can be qualified for sell, refi, roof, HVAC, and solar use cases at the same time. See the Propensity Scores section below for the full schema, score ranges, and how to filter on them.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
id
path
integer
Yes
The LeadList id from /execute/.
page
query
integer
No
Page number (default 1).
per_page
query
integer
No
Rows per page, 1-500 (default 100).

Example Request

curl 'https://tracerfy.com/v1/api/lead-builder/42/rows/?page=1&per_page=100' \
  -H 'Authorization: Bearer '

Example Response 200

{
  "lead_list_id": 42,
  "total_rows": 500,
  "page": 1,
  "per_page": 100,
  "total_pages": 5,
  "rows": [
    {
      "address": "742 Evergreen Terrace",
      "city": "Phoenix",
      "state": "AZ",
      "zip_code": "85032",
      "county": "Maricopa",
      "property_type": "SFR",
      "year_built": 1985,
      "beds": 4,
      "baths": 2.5,
      "building_size_sqft": 2140,
      "lot_size_sqft": 8712,
      "estimated_value": 485000,
      "estimated_equity": 298000,
      "equity_percent": 61.4,
      "assessed_value": 362000,
      "open_mortgage_balance": 134500,
      "lender_name": "Wells Fargo",
      "estimated_mortgage_payment": 987,
      "total_properties_owned": 2,
      "total_portfolio_value": 910000,
      "roof_material": "Composition Shingle",
      "roof_construction": "Gable",
      "flood_zone": false,
      "cash_buyer": false,
      "corporate_owned": false,
      "owner_1_first_name": "JANE",
      "owner_1_last_name": "DOE",
      "owner_2_first_name": "",
      "owner_2_last_name": "",
      "mail_address": "742 Evergreen Terrace",
      "mail_city": "Phoenix",
      "mail_state": "AZ",
      "mail_zip": "85032",
      "primary_phone": "4805551234",
      "primary_phone_type": "Mobile",
      "primary_phone_carrier": "T-Mobile",
      "primary_phone_dnc": false,
      "primary_phone_tcpa": false,
      "mobile_1": "4805559876",
      "mobile_1_dnc": true,
      "mobile_1_tcpa": false,
      "email_1": "[email protected]",
      "email_2": "",
      "email_3": "",
      "has_contact": true,
      "contact_clean": true,
      "absentee_owner": false,
      "owner_occupied": true,
      "high_equity": true,
      "vacant": false,
      "pre_foreclosure": false,
      "free_clear": false,
      "last_sale_date": "2009-04-15",
      "last_sale_price": 187000,
      "prior_sale_date": "2001-08-22",
      "prior_sale_price": 142000,
      "document_type": "Warranty Deed",
      "recording_date": "2009-04-17",
      "sell_propensity_score": 24,
      "sell_propensity_category": "Low",
      "sell_propensity_factors": [
        {
          "name": "owner_occupied",
          "points": 8,
          "reason": "Owner-occupied β€” primary residence"
        },
        {
          "name": "years_owned",
          "points": 7,
          "reason": "Owned 16 years β€” moderate equity accumulation"
        }
      ],
      "refi_propensity_score": 33,
      "refi_propensity_category": "Low",
      "refi_propensity_factors": [
        {
          "name": "high_equity",
          "points": 15,
          "reason": "High equity β€” strong candidate for cash-out refi"
        },
        {
          "name": "owner_occupied",
          "points": 8,
          "reason": "Owner-occupied β€” primary residence refinance more likely"
        },
        {
          "name": "years_owned",
          "points": 10,
          "reason": "Owned 16 years β€” likely has equity to tap"
        }
      ],
      "roof_renovate_propensity_score": 47,
      "roof_renovate_propensity_category": "Medium",
      "roof_renovate_propensity_factors": [
        {
          "name": "owner_occupied",
          "points": 15,
          "reason": "Owner-occupied β€” decision-maker present"
        },
        {
          "name": "high_equity",
          "points": 12,
          "reason": "High equity β€” affordability for $20K+ project"
        },
        {
          "name": "older_home",
          "points": 12,
          "reason": "Built 1985 β€” typical roof end-of-life window"
        }
      ],
      "hvac_renovate_propensity_score": 52,
      "hvac_renovate_propensity_category": "Medium",
      "hvac_renovate_propensity_factors": [
        {
          "name": "owner_occupied",
          "points": 18,
          "reason": "Owner-occupied β€” decision-maker present"
        },
        {
          "name": "older_home",
          "points": 14,
          "reason": "Built 1985 β€” HVAC typically replaced every 15-20 years"
        },
        {
          "name": "high_equity",
          "points": 12,
          "reason": "High equity β€” affordability for system upgrade"
        }
      ],
      "solar_renovate_propensity_score": 71,
      "solar_renovate_propensity_category": "High",
      "solar_renovate_propensity_factors": [
        {
          "name": "owner_occupied",
          "points": 20,
          "reason": "Owner-occupied β€” decision-maker for long-term install"
        },
        {
          "name": "high_equity",
          "points": 18,
          "reason": "High equity β€” financing or cash-out available for install"
        },
        {
          "name": "high_value_property",
          "points": 18,
          "reason": "Property value $485K β€” high-value home, typically sunny region"
        }
      ]
    },
    {
      "address": "1200 Oak Blvd",
      "city": "Phoenix",
      "state": "AZ",
      "zip_code": "85018",
      "county": "Maricopa",
      "property_type": "SFR",
      "year_built": 1972,
      "beds": 3,
      "baths": 2.0,
      "building_size_sqft": 1680,
      "lot_size_sqft": 6200,
      "estimated_value": 395000,
      "estimated_equity": 395000,
      "equity_percent": 100.0,
      "assessed_value": 288000,
      "open_mortgage_balance": 0,
      "lender_name": "",
      "estimated_mortgage_payment": 0,
      "total_properties_owned": 1,
      "total_portfolio_value": 395000,
      "roof_material": "Tile/Clay",
      "roof_construction": "Hip",
      "flood_zone": false,
      "cash_buyer": false,
      "corporate_owned": false,
      "owner_1_first_name": "ROBERT",
      "owner_1_last_name": "SMITH",
      "owner_2_first_name": "LINDA",
      "owner_2_last_name": "SMITH",
      "mail_address": "PO Box 4412",
      "mail_city": "Scottsdale",
      "mail_state": "AZ",
      "mail_zip": "85261",
      "primary_phone": "6025559900",
      "primary_phone_type": "Landline",
      "primary_phone_carrier": "CenturyLink",
      "primary_phone_dnc": false,
      "primary_phone_tcpa": false,
      "mobile_1": "",
      "mobile_1_dnc": false,
      "mobile_1_tcpa": false,
      "email_1": "[email protected]",
      "email_2": "",
      "email_3": "",
      "has_contact": true,
      "contact_clean": true,
      "absentee_owner": true,
      "owner_occupied": false,
      "high_equity": true,
      "vacant": false,
      "pre_foreclosure": false,
      "free_clear": true,
      "last_sale_date": "1998-11-03",
      "last_sale_price": 95000,
      "prior_sale_date": null,
      "prior_sale_price": null,
      "document_type": "Warranty Deed",
      "recording_date": "1998-11-05",
      "sell_propensity_score": 47,
      "sell_propensity_category": "Medium",
      "sell_propensity_factors": [
        {
          "name": "years_owned",
          "points": 12,
          "reason": "Owned 27 years β€” long tenure, high equity accumulation"
        },
        {
          "name": "absentee_owner",
          "points": 8,
          "reason": "Absentee owner β€” less attached to property"
        },
        {
          "name": "free_clear",
          "points": 4,
          "reason": "Free and clear β€” no mortgage friction at sale"
        },
        {
          "name": "aging_property",
          "points": 4,
          "reason": "Built 1972 β€” significant deferred-maintenance burden"
        }
      ],
      "refi_propensity_score": 18,
      "refi_propensity_category": "Low",
      "refi_propensity_factors": [
        {
          "name": "free_clear",
          "points": 6,
          "reason": "Free and clear β€” could take on a new mortgage product"
        }
      ],
      "roof_renovate_propensity_score": 18,
      "roof_renovate_propensity_category": "Low",
      "roof_renovate_propensity_factors": [
        {
          "name": "high_equity",
          "points": 12,
          "reason": "High equity β€” affordability for $20K+ project"
        },
        {
          "name": "absentee_penalty",
          "points": -10,
          "reason": "Absentee owner β€” investors defer discretionary projects"
        }
      ],
      "hvac_renovate_propensity_score": 22,
      "hvac_renovate_propensity_category": "Low",
      "hvac_renovate_propensity_factors": [
        {
          "name": "high_equity",
          "points": 12,
          "reason": "High equity β€” affordability for system upgrade"
        },
        {
          "name": "absentee_penalty",
          "points": -10,
          "reason": "Absentee owner β€” landlords delay HVAC replacement"
        }
      ],
      "solar_renovate_propensity_score": 8,
      "solar_renovate_propensity_category": "Low",
      "solar_renovate_propensity_factors": [
        {
          "name": "absentee_penalty",
          "points": -25,
          "reason": "Absentee owner β€” solar installs require resident decision-maker"
        }
      ]
    },
    "... 98 more rows in this page"
  ]
}

List still processing

{
  "error": "Lead list is still processing. Poll the status endpoint until complete.",
  "status": "pending"
}

Not found

{
  "error": "Lead list not found."
}
POST

Single-Address Lookup (Synchronous)

/v1/api/lead-builder/lookup/
Description: Synchronous single-address version of /execute/ β€” one address in, one full lead row out. JSON response, no CSV. Use this when you already have a specific address and want the complete data (property attributes, owner, full skip trace) in a single API call.

Billing β€” 10 credits per property hit:
β€’ Property found + skip trace hit β†’ 10 credits, full phones/emails + all compliance flags
β€’ Property found + skip trace miss β†’ 10 credits, full property data, empty contacts block
β€’ Property NOT found β†’ 0 credits, hit: false

Priced at 2Γ— the /v1/api/trace/lookup/ endpoint (5 credits) because this lookup returns the full property dossier (50+ CSV columns) in addition to skip-trace contacts. If you only need phones and emails for an address (no property attributes), use instant trace instead β€” same skip-trace data, half the cost.

The response shape: the property, owner, and contacts blocks together contain every column from the CSV schema β€” flatten them to get a single row ready for pandas / spreadsheet ingestion.

ZIP code: optional but strongly recommended β€” without it, common street names can match the wrong property in a large city.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
address
body
string
Yes
Property street address. Example: "4521 E Monte Cristo Ave".
city
body
string
Yes
Property city.
state
body
string
Yes
Property state (2-letter code).
zip_code
body
string
No
Property ZIP. Optional but strongly recommended for accuracy.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/lead-builder/lookup/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{
    "address": "4521 E Monte Cristo Ave",
    "city": "Phoenix",
    "state": "AZ",
    "zip_code": "85032"
  }'

Example Response 200

// Hit β€” 10 credits deducted
{
  "hit": true,
  "credits_deducted": 10,
  "skip_trace_hit": true,
  "property": {
    "address": "4521 E Monte Cristo Ave",
    "city": "Phoenix",
    "state": "AZ",
    "zip_code": "85032",
    "county": "Maricopa",
    "latitude": 33.6,
    "longitude": -112.0,
    "apn": "123-45-6789",
    "subdivision": "Paradise Park",
    "property_type": "SFR",
    "property_use": "Single Family",
    "land_use": "Residential",
    "year_built": 1978,
    "beds": 4,
    "baths": 2.5,
    "units_count": 1,
    "stories": 1,
    "building_size_sqft": 2140,
    "lot_size_sqft": 8712,
    "has_ac": true,
    "has_garage": true,
    "has_pool": false,
    "has_basement": false,
    "has_deck": true,
    "estimated_value": 485000,
    "estimated_equity": 298000,
    "equity_percent": 61.4,
    "assessed_value": 362000,
    "last_sale_date": "2009-04-15",
    "last_sale_price": 187000,
    "years_owned": 17,
    "prior_sale_date": "2001-08-22",
    "prior_sale_price": 142000,
    "open_mortgage_balance": 134500,
    "lender_name": "Wells Fargo",
    "estimated_mortgage_payment": 987,
    "total_properties_owned": 2,
    "total_portfolio_value": 910000,
    "cash_buyer": false,
    "corporate_owned": false,
    "roof_material": "Composition Shingle",
    "roof_construction": "Gable",
    "flood_zone": false,
    "document_type": "Warranty Deed",
    "recording_date": "2009-04-17",
    "absentee_owner": false,
    "owner_occupied": true,
    "vacant": false,
    "free_clear": false,
    "high_equity": true,
    "pre_foreclosure": false,
    "tax_delinquent": false,
    "mls_active": false,
    "mls_pending": false,
    "mls_cancelled": false,
    "mls_days_on_market": null,
    "mls_listing_price": null,
    "adjustable_rate": false,
    "investor_buyer": false,
    "sell_propensity_score": 24,
    "sell_propensity_category": "Low",
    "sell_propensity_factors": [
      {
        "name": "owner_occupied",
        "points": 8,
        "reason": "Owner-occupied β€” primary residence"
      },
      {
        "name": "years_owned",
        "points": 10,
        "reason": "Owned 17 years β€” significant equity likely"
      }
    ],
    "refi_propensity_score": 33,
    "refi_propensity_category": "Low",
    "refi_propensity_factors": [
      {
        "name": "high_equity",
        "points": 15,
        "reason": "High equity β€” strong candidate for cash-out refi"
      },
      {
        "name": "owner_occupied",
        "points": 8,
        "reason": "Owner-occupied β€” primary residence refinance more likely"
      },
      {
        "name": "years_owned",
        "points": 10,
        "reason": "Owned 17 years β€” likely has equity to tap"
      }
    ],
    "roof_renovate_propensity_score": 49,
    "roof_renovate_propensity_category": "Medium",
    "roof_renovate_propensity_factors": [
      {
        "name": "owner_occupied",
        "points": 15,
        "reason": "Owner-occupied β€” decision-maker present"
      },
      {
        "name": "high_equity",
        "points": 12,
        "reason": "High equity β€” affordability for $20K+ project"
      },
      {
        "name": "older_home",
        "points": 14,
        "reason": "Built 1978 β€” typical roof end-of-life window"
      }
    ],
    "hvac_renovate_propensity_score": 54,
    "hvac_renovate_propensity_category": "Medium",
    "hvac_renovate_propensity_factors": [
      {
        "name": "owner_occupied",
        "points": 18,
        "reason": "Owner-occupied β€” decision-maker present"
      },
      {
        "name": "older_home",
        "points": 16,
        "reason": "Built 1978 β€” HVAC typically replaced every 15-20 years"
      },
      {
        "name": "high_equity",
        "points": 12,
        "reason": "High equity β€” affordability for system upgrade"
      }
    ],
    "solar_renovate_propensity_score": 73,
    "solar_renovate_propensity_category": "High",
    "solar_renovate_propensity_factors": [
      {
        "name": "owner_occupied",
        "points": 20,
        "reason": "Owner-occupied β€” decision-maker for long-term install"
      },
      {
        "name": "high_equity",
        "points": 18,
        "reason": "High equity β€” financing or cash-out available for install"
      },
      {
        "name": "high_value_property",
        "points": 18,
        "reason": "Property value $485K β€” high-value home, sunny region"
      }
    ]
  },
  "owners": [
    {
      "first_name": "JANET",
      "last_name": "MORRIS"
    },
    {
      "first_name": "ROBERT",
      "last_name": "MORRIS"
    }
  ],
  "mailing_address": {
    "address": "4521 E Monte Cristo Ave",
    "city": "Phoenix",
    "state": "AZ",
    "zip": "85032"
  },
  "contacts": {
    "phones": [
      {
        "number": "4805551234",
        "type": "Mobile",
        "dnc": false,
        "tcpa": false,
        "carrier": "T-Mobile",
        "rank": 1
      },
      {
        "number": "4805559876",
        "type": "Mobile",
        "dnc": true,
        "tcpa": false,
        "carrier": "AT&T",
        "rank": 2
      },
      {
        "number": "4805550100",
        "type": "Landline",
        "dnc": false,
        "tcpa": false,
        "carrier": "CenturyLink",
        "rank": 3
      }
    ],
    "emails": [
      {
        "email": "[email protected]",
        "rank": 1
      }
    ],
    "litigator": false,
    "has_contact": true,
    "contact_clean": false
  }
}

// Miss β€” address not found, 0 credits
{
  "hit": false,
  "credits_deducted": 0,
  "address": "999 Nowhere Blvd",
  "city": "Austin",
  "state": "TX",
  "zip_code": "78701"
}

Insufficient credits

{
  "error": "Insufficient credits. Lead Builder lookup requires 10 credits per hit. You have 2 credits."
}

Unpaid invoice β€” account suspended

{
  "error": "Your account has been temporarily suspended due to unpaid invoices. Please contact [email protected] to resolve outstanding payments."
}

Upstream temporarily unavailable

{
  "error": "Lookup service temporarily unavailable. Please try again."
}
POST

Address Autocomplete

/v1/api/lead-builder/autocomplete/
Description: Resolve a free-text address string to canonical property records. Use this before calling /lookup/ to validate that an address exists in our database β€” and to get back the canonical city/zip values our lookup endpoint expects.

FREE β€” zero credits charged. This is a pre-flight validation tool. Use it as much as needed before paying for a full lookup.

When to use it

  • Before /lookup/ on messy data: CRM exports, hand-typed lists, web form submissions β€” any address you're not 100% sure about. Run it through autocomplete first; only pay for /lookup/ on resolved addresses.
  • Neighborhood-vs-USPS city: Customers often type neighborhood names ("Williamsburg", "Park Slope", "Highland Park") that USPS canonicalizes to a different city label ("Long Island City", "Brooklyn", "Los Angeles"). Our /lookup/ endpoint requires the canonical city; this endpoint tells you what it is.
  • Typo / suffix variation: "123 Main" vs "123 Main St" vs "123 Main Street" β€” autocomplete normalizes all to the canonical form.
  • Address verification at scale: validating thousands of addresses without burning credits.

Rate limit

30 requests per minute per account. If you exceed this you'll get a 429 Too Many Requests with an Autocomplete rate limit exceeded message β€” back off and retry. The throttle is purely a fair-use guard so individual accounts can't monopolize the underlying address-resolution capacity.
What you get back

An array of up to 10 best-match property records. Each record contains:

  • Display β€” title (the full one-line label, e.g. "742 Evergreen Terrace, Brooklyn, NY, 11211").
  • Canonical address parts β€” street_address, house, street, city, state, zip, county. The address field is the full formatted display string (e.g. "742 Evergreen Terrace, Brooklyn, NY, 11211") β€” do not re-pass it as address on /lookup/.
  • Geographic identifiers β€” state_fips, county_fips, fips (combined 5-digit code), and apn (Assessor's Parcel Number). These are public US-government identifiers, useful for cross-referencing county records.
  • Geometry β€” latitude, longitude, and location (WKT POINT format) for mapping.
If no matches, results is an empty array.

Picking a result programmatically

Every result is a property address, so results[0] is the best match. Pass street_address as address, and city, state, zip as-is to /lookup/:

# Pseudocode
match = resp["results"][0] if resp["results"] else None
if match:
    POST /v1/api/lead-builder/lookup/ {
        "address":  match["street_address"],   # NOT match["address"]
        "city":     match["city"],
        "state":    match["state"],
        "zip_code": match["zip"],
    }

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
search
body
string
Yes
The address string to resolve. Minimum 2 characters. Whitespace and casing don't matter β€” the resolver handles both.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/lead-builder/autocomplete/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"search": "742 Evergreen Terr Williamsburg NY"}'

Example Response 200

{
  "query": "742 Evergreen Terr, Williamsburg NY",
  "credits_deducted": 0,
  "results": [
    {
      "title": "742 Evergreen Terrace, Brooklyn, NY, 11211",
      "address": "742 Evergreen Terrace, Brooklyn, NY, 11211",
      "street_address": "742 Evergreen Terrace",
      "house": "742",
      "street": "Evergreen Terrace",
      "city": "Brooklyn",
      "state": "NY",
      "zip": "11211",
      "county": "Kings County",
      "state_fips": "36",
      "county_fips": "047",
      "fips": "36047",
      "apn": "03145-0042",
      "latitude": 40.7081,
      "longitude": -73.9571,
      "location": "POINT (-73.9571 40.7081)"
    }
  ]
}

Missing search field

{
  "error": "Missing 'search' field. Pass {\"search\": \"<address text>\"} in the request body."
}

Rate limit exceeded

{
  "status": 429,
  "error": "Autocomplete rate limit exceeded. Max 30 requests per minute."
}

Upstream temporarily unavailable

{
  "error": "Address resolution service temporarily unavailable. Please try again."
}
POST

Lead Builder Webhooks

Account.webhook_url
Description: When a Lead Builder list completes, Tracerfy POSTs the result to the webhook_url configured on your account β€” the same account-level URL used for skip trace and DNC webhooks. This eliminates the need to poll /status/ β€” your server gets notified the moment the CSV is ready.

How to use: set your webhook_url in your account settings. When any lead list finishes (success or failure), Tracerfy sends a POST with the payload below. Your endpoint should return 2xx within 10 seconds.

Retry: Tracerfy does not retry failed webhook deliveries. If your server is down when the webhook fires, use /status/ as a fallback to check completion.

Headers

  • Content-Type = application/json

Example Request

Tracerfy sends this JSON to your Account.webhook_url when a lead list completes.

Example Response 200

{
  "id": 42,
  "type": "lead_list",
  "name": "Phoenix Q2 Prospects",
  "strategy": "high_equity_absentee",
  "source": "api",
  "created_at": "2026-04-11T18:23:00Z",
  "completed_at": "2026-04-11T18:37:42Z",
  "pending": false,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/lead_list_a1b2c3d4.csv",
  "requested_count": 500,
  "actual_count": 487,
  "credits_deducted": 2435
}
POST

AI Assist (TraceAI)

/v1/api/lead-builder/ai-assist/
Description: Translate a plain-English description of your ideal customer into a structured strategy + geography + filter_overrides spec you can pipe straight into /preview/ or /execute/. This is the fastest way to build a lead list from code β€” one call to describe, one call to run.

Billing: 1 credit per successful response. Failed calls (503) are not charged.

When the AI isn't sure: if your prompt is ambiguous ('Springfield', 'LA'), the response will include needs_clarification: true, a clarifying_question, and a conversation_id. To reply, pass the same conversation_id along with the user's answer in a new call β€” the AI loads the full conversation history and picks up where it left off.

Conceptual questions like "what is a tired landlord" return needs_clarification: true with the explanation in rationale.summary β€” don't run a search on those, ask the user where they want to target first.

Neighborhood-level targeting: say "plumbing leads in South Side Chicago" or "downtown Nashville probate" and TraceAI will pick the ZIP codes that cover the area from its general knowledge. No need to hand-roll ZIP lists.

Headers

  • Authorization = Bearer <YOUR_TOKEN>
  • Content-Type = application/json

Parameters

Name
In
Type
Required
Description
prompt
body
string
Yes
Plain-English description of the target audience. 5-2000 characters. Example: 'plumbing leads in South Side Chicago' or 'absentee owners with 50%+ equity in Tampa built before 1990'.
conversation_id
body
uuid
No
UUID from a previous response. Pass this to continue a clarification thread β€” the AI loads all prior turns automatically.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/lead-builder/ai-assist/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"prompt": "plumbing leads in South Side Chicago"}'

Example Response 200

// Successful β€” filters applied, ready to pipe into /preview/ or /execute/
{
  "strategy": "custom",
  "strategy_label": "Custom",
  "geography": {
    "mode": "zips",
    "zip_codes": [
      "60609",
      "60615",
      "60617",
      "60619",
      "60620",
      "60621"
    ]
  },
  "filter_overrides": {
    "property_type": "SFR",
    "year_built_max": 2000,
    "absentee_owner": false
  },
  "rationale": {
    "summary": "Owner-occupied single-family homes in the South Side Chicago ZIP codes built before 2000 β€” older plumbing systems are common in this age range.",
    "steps": [],
    "assumptions": [],
    "warnings": [
      "Applied Year Built ≀ 2000. To include rentals, remove the absentee-owner filter."
    ]
  },
  "confidence": 0.88,
  "needs_clarification": false,
  "clarifying_question": null,
  "conversation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "credits_deducted": 1
}

// Clarification needed β€” AI needs more info before it can search
{
  "strategy": "custom",
  "strategy_label": "Custom",
  "geography": {
    "mode": "city",
    "cities": [
      "(pending)"
    ]
  },
  "filter_overrides": {},
  "rationale": {
    "summary": "I can help find leads in Austin, but I need to know what kind. Investors, distressed sellers, homeowners for a service, or something else?",
    "steps": [],
    "assumptions": [],
    "warnings": []
  },
  "confidence": 0.3,
  "needs_clarification": true,
  "clarifying_question": "What kind of leads are you looking for? Are you targeting investors, distressed sellers, or homeowners for a specific service?",
  "conversation_id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
  "credits_deducted": 1
}

Insufficient credits

{
  "error": "Insufficient credits. You need at least 1 credit to use AI assist. Your balance is 0 credits."
}

AI temporarily unavailable

{
  "error": "AI assist temporarily unavailable. Please try again or build filters manually via /preview/."
}
REF

Filter Reference

Accepted keys for filter_overrides
Description:

Every key accepted in filter_overrides, grouped for readability. Unknown keys are rejected with a 400.

GroupKeys
Propertyproperty_type, property_types, beds_min, beds_max, baths_min, baths_max, units_min, units_max, building_size_min, building_size_max, lot_size_min, lot_size_max, year_built_min, year_built_max, stories_min, stories_max, rooms_min, rooms_max, pool, garage, basement, deck, mfh_2to4, mfh_5plus
Value & Equityvalue_min, value_max, assessed_value_min, assessed_value_max, estimated_equity, estimated_equity_min, estimated_equity_max, equity, equity_operator, high_equity, free_clear, ltv_min, ltv_max
Ownershipabsentee_owner, in_state_owner, out_of_state_owner, individual_owned, trust_owned, corporate_owned, cash_buyer, investor_buyer, private_lender, properties_owned_min, properties_owned_max, years_owned_min, years_owned_max
Portfolio signalsportfolio_value_min/max, portfolio_equity_min/max, portfolio_mortgage_balance_min/max, portfolio_purchased_last6_min/max, portfolio_purchased_last12_min/max
Distressvacant, pre_foreclosure, pre_foreclosure_date_min, pre_foreclosure_date_max, auction, reo, notice_type, search_range
MLSmls_active, mls_pending, mls_cancelled, mls_days_on_market_min, mls_days_on_market_max, mls_listing_price_min
Mortgagemortgage_min, mortgage_max, adjustable_rate, assumable, loan_type_code_first, open_mortgages_min, open_mortgages_max
Sale historylast_sale_date_min, last_sale_date_max, last_sale_price_min, last_sale_price_max, last_sale_arms_length
Mailing addressmail_city, mail_state, mail_zip, mail_county
Environmentflood_zone, flood_zone_type
REF

Propensity Scores

Five scores included on every lead row
Description: Every row returned by /rows/, /lookup/, and the CSV export carries five independent propensity scores. Each score quantifies how strongly the property's signals match a specific use case β€” selling, refinancing, roof replacement, HVAC replacement, or solar installation. The same property can score High in one and Low in another, so a single lead list can serve multiple downstream campaigns.

Score range and interpretation

Each score is an integer from 0 to 100. The category column rolls the score up into one of three tiers using these thresholds:

Score rangeCategoryWhat it means
70–100HighMultiple strong signals are present. Prioritize these leads first.
40–69MediumSome positive signals. Worth contacting but expect lower conversion than High.
0–39LowFew or weak signals for this use case. Skip unless you have other intent data.

Recommended action thresholds

  • Score β‰₯ 70 (High): include in primary outreach. These are your best leads for the corresponding use case.
  • Score 50–69: include in secondary outreach if your list is small, or as a backup pool when High leads run out.
  • Score 40–49: typically skip unless you have additional context (local market knowledge, prior contact history, etc.).
  • Score < 40: exclude from outreach for this use case. The lead may still be valuable for a different vertical with a higher score.

Filtering by score in your code

The score is a plain integer column, so post-filtering is straightforward in Excel, pandas, SQL, or any CRM:

# pandas
df_high_solar = df[df['solar_renovate_propensity_score'] >= 70]

# SQL
SELECT * FROM rows WHERE refi_propensity_score >= 50 ORDER BY refi_propensity_score DESC;

# Excel filter
AutoFilter on 'roof_renovate_propensity_category' = 'High'

Score field schema

Each of the 5 propensity verticals exposes 3 fields on every row:

VerticalUse caseScore fieldCategory fieldFactors field
SellWholesalers, real estate investorssell_propensity_scoresell_propensity_categorysell_propensity_factors
RefinanceMortgage brokers, lendersrefi_propensity_scorerefi_propensity_categoryrefi_propensity_factors
Roof renovateRoofing contractorsroof_renovate_propensity_scoreroof_renovate_propensity_categoryroof_renovate_propensity_factors
HVAC renovateHVAC contractorshvac_renovate_propensity_scorehvac_renovate_propensity_categoryhvac_renovate_propensity_factors
Solar renovateSolar installerssolar_renovate_propensity_scoresolar_renovate_propensity_categorysolar_renovate_propensity_factors

The factors array β€” explainability

Each *_factors field is a JSON array of {name, points, reason} objects describing exactly which signals fired and how much each contributed to the score. Use this to explain to your end-customer why a lead was prioritized, or to debug why a lead scored higher or lower than expected.

Important notes

  • Scores are deterministic snapshots computed at the time the lead list was built. They are not refreshed automatically.
  • Same property, different verticals. A property can score High for solar (owner-occupied, high-equity, sunny region) and Low for sell (no distress signals). This is expected and intentional β€” the scores measure different things.
  • The scores are signal-density indicators, not predictions. A score of 80 means the lead matches more of the relevant signals than a lead at 40, not that it has an 80% probability of conversion. Use them to prioritize, not as a forecast.
  • Realistic precision target: 65–75%. Of leads scored High, expect 65–75% to actually be receptive β€” better than random selection, but not a guarantee.