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>
REF

Authentication, Errors & Rate Limits

Applies to every /v1/api/ endpoint
Description: Every endpoint requires a Bearer token in the Authorization header: Authorization: Bearer <YOUR_TOKEN>. Requests without a valid token get a 401.

Status codes you may receive:
  • 200 OK β€” success (synchronous endpoints).
  • 202 Accepted β€” async job accepted and queued (e.g. Lead Builder execute).
  • 400 Bad Request β€” malformed body, missing/invalid parameter, or a column named in your request is not present in the uploaded data.
  • 401 Unauthorized β€” missing, malformed, or invalid/expired Bearer token.
  • 402 Payment Required β€” insufficient credits for the requested work.
  • 403 Forbidden β€” account suspended (unpaid invoices or API access disabled), or you tried to access a resource that belongs to another account.
  • 404 Not Found β€” the resource ID does not exist (or is not yours β€” unknown and cross-account IDs both return 404 to prevent ID enumeration).
  • 405 Method Not Allowed β€” wrong HTTP method for the route.
  • 409 Conflict β€” the resource is not ready yet (e.g. reading rows of a lead list that is still processing).
  • 429 Too Many Requests β€” a rate limit was exceeded. Back off and retry; the response body includes how many requests were counted in the window.
  • 500 Internal Server Error β€” an unexpected error. Retry; if it persists, contact support.
  • 502 / 503 β€” the request couldn't be completed right away due to a temporary service delay. This usually resolves on its own. If it persists, contact support.
Rate limits (per account):
  • Batch Trace & APN Batch Trace β€” 10 submissions per 5 minutes.
  • Instant Trace, APN Instant Lookup & Lead Builder Lookup β€” 500 lookups per minute (shared counter).
  • DNC Scrub β€” 10 scrubs per 5 minutes.
  • DNC Instant Lookup β€” 30 lookups per minute.
  • Fetch all Queues β€” 1 request per 20 seconds.
  • Lead Builder Preview β€” 500 previews per hour.
  • Lead Builder Execute β€” 10 lists per hour and 50 per day.
  • Address Autocomplete β€” 30 requests per minute.
The insufficient-credits (402) and suspended-account (403) message wording varies slightly per endpoint, but the shape and status code are the same everywhere. Representative bodies are below.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

401 Unauthorized β€” missing or invalid token

{
  "detail": "Authentication credentials were not provided."
}

400 Bad Request — field validation (detail is a field→messages map)

{
  "address": [
    "This field is required."
  ],
  "state": [
    "This field is required."
  ]
}

402 Payment Required β€” insufficient credits

// When the account cannot use monthly billing
{
  "error": "Insufficient credits. Instant trace requires 5 credits per lookup. You have 0 credits."
}

// When credits are short and no payment method is on file
{
  "error": "Insufficient credits. Instant trace requires 5 credits per lookup. Please add credits or a payment method."
}

403 Forbidden β€” account suspended

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

// API access disabled for this account
{
  "error": "api_disabled",
  "detail": "Your API access has been suspended. Please contact support at [email protected].",
  "status": 403
}

404 Not Found β€” unknown or cross-account resource ID

{
  "error": "No Queue Found with ID 123"
}

429 Too Many Requests β€” rate limited

// Most endpoints β€” includes the count seen in the window
{
  "status": 429,
  "error": "Rate limit exceeded. Max 500 lookups per minute.",
  "lookups_in_window": 500
}

// Fetch all Queues (20-second throttle)
{
  "error": "Rate limit exceeded. Retry in intervals of 20 seconds.",
  "retry_in": "3 seconds"
}
REF

Sandbox / Testing Environment

https://mock.tracerfy.com/v1/api/
Description: Before you spend a single credit, build and test your integration against the free hosted sandbox at https://mock.tracerfy.com. It mirrors this exact API β€” same paths, methods, field names, and response shapes β€” but returns realistic fake data. Nothing is charged and no credits are consumed.

Going live is a one-line change: develop against https://mock.tracerfy.com/v1/api/, then swap the host to https://tracerfy.com/v1/api/ and use your real token. Nothing else about your code changes.
  • Auth: any non-empty Bearer token authenticates β€” no real key needed. (The reserved value INVALID_TOKEN always returns 401 so you can test your unauthorized path.)
  • Deterministic: the same request always returns the same data (it's seeded from your inputs), so your test assertions stay stable. Only meta.request_id and meta.timestamp vary between calls.
  • Full coverage: every endpoint in these docs β€” batch & instant trace, parcel/APN, DNC, property search, saved templates, and property monitors.
  • Interactive docs: browse and try every endpoint at https://mock.tracerfy.com/docs.
Magic values β€” force a specific scenario on demand. Anything you send that isn't a magic value flows through to a normal deterministic fake response. The values below instead trigger a fixed outcome, so you can exercise every branch of your client without hunting for real data that happens to hit or miss:
  • Numeric path IDs β€” use an HTTP status code as any {id} to reproduce that scenario: 404 not found, 403 cross-account, 409 still processing, 0 a pending job. e.g. GET /v1/api/property-monitors/404/404.
  • String sentinels β€” embed a keyword in the primary string field (address, phone, a monitor name, a strategy value, or a CSV *_column): NO_CREDITS→402, SUSPENDED→403, RATE_LIMIT→429, SERVER_ERROR→500, UNAVAILABLE→503, MISSING_COLUMN→400 (CSV), NO_MATCH→200 empty, MULTI→200 multiple results, CAP_REACHED→400 (monitor cap). The literal address 999 Nowhere Blvd behaves as a miss.
The sandbox is for development only β€” it returns fabricated data, so never point production traffic at it.

Headers

  • Authorization = Bearer <ANY_NON_EMPTY_TOKEN>

Example Request

# Test against the sandbox β€” any token works, nothing is billed
curl -X POST 'https://mock.tracerfy.com/v1/api/trace/lookup/' \
  -H 'Authorization: Bearer sandbox_test_token' \
  -H 'Content-Type: application/json' \
  -d '{"address":"123 Main St","city":"Austin","state":"TX","zip":"78701"}'

# Force a scenario with a magic value (402 insufficient credits)
curl -X POST 'https://mock.tracerfy.com/v1/api/trace/lookup/' \
  -H 'Authorization: Bearer sandbox_test_token' \
  -H 'Content-Type: application/json' \
  -d '{"address":"NO_CREDITS","city":"Austin","state":"TX"}'

# Ready for real data? Change the host and use your real token
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"}'

Example Response 200 OK

// POST /v1/api/trace/lookup/ on the sandbox β€” the exact body the first curl above
// returns. Deterministic: the same request always returns this data (only meta varies).
{
  "address": "123 Main St",
  "city": "Austin",
  "state": "TX",
  "zip": "78701",
  "find_owner": true,
  "hit": true,
  "persons_count": 1,
  "credits_deducted": 5,
  "persons": [
    {
      "first_name": "Sandra",
      "last_name": "Dean",
      "full_name": "Sandra Dean",
      "dob": "1958-12-14",
      "age": "67",
      "deceased": true,
      "property_owner": true,
      "litigator": false,
      "mailing_address": {
        "street": "469 Amy Pines Suite 707",
        "city": "Christinebury",
        "state": "CT",
        "zip": "50627"
      },
      "phones": [
        {
          "number": "5088697674",
          "type": "Mobile",
          "dnc": false,
          "tcpa": false,
          "carrier": "COMCAST PHONE LLC",
          "rank": 1
        },
        {
          "number": "6478388352",
          "type": "Landline",
          "dnc": true,
          "tcpa": false,
          "carrier": "US CELLULAR",
          "rank": 2
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        }
      ]
    }
  ],
  "meta": {
    "request_id": "req_b0e2ba54941820e3009e83c0cd14dda6",
    "timestamp": "2026-07-20T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

Magic value NO_CREDITS β†’ 402 (deterministic)

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

Reserved token INVALID_TOKEN β†’ 401

{
  "detail": "Authentication credentials were not provided."
}
REF

Response Metadata

Applies to every /v1/api/ endpoint
Description: Every response carries an X-Request-Id response header β€” a unique id Tracerfy assigns to that request. Use it to correlate a specific response with your own application logs and retries, and quote it when contacting support. The id is always assigned server-side; any X-Request-Id you send on the request is ignored.

In addition, every response whose body is a JSON object includes a meta block:
  • request_id β€” the same value as the X-Request-Id header.
  • timestamp β€” when the response was generated (ISO 8601, UTC).
  • api_version β€” the response-schema version that served the request.
meta is additive β€” new fields may be added over time, so treat unknown keys as optional and ignore them. Endpoints that return a top-level JSON array (e.g. Fetch all Queues and Fetch Single Queue) keep their bare-array body and do not include a meta block β€” read the X-Request-Id header for those. The AI-assist endpoint (/v1/api/property-search/ai-assist/) also returns no meta block (it still carries the X-Request-Id header).

Headers

  • X-Request-Id = req_1a2b3c… (present on every response)

meta block (present on every object response)

// Example: the Analytics response, with the meta block appended
{
  "total_queues": 12,
  "properties_traced": 18350,
  "queues_pending": 2,
  "queues_completed": 10,
  "balance": 940,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}
GET

Fetch all Queues

/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.

One record per input row that produced a match. Input rows where no person was found at the address don't appear in this response β€” there's no record to return. For the full row-aligned view (every input row alongside whatever was found, including misses), use the CSV at download_url on the queue object β€” that file contains all rows you submitted, with empty contact columns for rows that didn't match.

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": ""
  }
]

404 β€” No queue with that ID

{
  "error": "No Queue Found with ID 123"
}

403 β€” Queue belongs to another account

{
  "error": "You do not have permission to access this queue."
}
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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}
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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Column not found in your data

{
  "error": "Error in cleansing the data, please check the data and try again",
  "details": "'address' Not found in the data or not a valid column name"
}

400 β€” No usable rows

{
  "error": "No valid rows found after data cleaning. Please check your data and try again."
}

400 β€” Enhanced trace deprecated

{
  "error": "Enhanced trace has been deprecated. Please use 'normal' or 'custom' trace type."
}

403 β€” Custom trace not enabled for this account

{
  "error": "You don't have permission to use custom trace. Please contact support to enable this feature."
}

402 β€” Insufficient credits

{
  "error": "Insufficient credits for normal trace. You need 40 more credits to complete this request. Please add credits to your account or add a payment method for monthly billing."
}
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 + TCPA litigator status, carrier, type, rank), and all emails.

⚠️ Compliance: Phones returning litigator: true or dnc: true should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.

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,
          "tcpa": false,
          "carrier": "T-MOBILE USA INC.",
          "rank": 1
        },
        {
          "number": "5125550200",
          "type": "Landline",
          "dnc": true,
          "tcpa": false,
          "carrier": "AT&T TEXAS",
          "rank": 2
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        }
      ]
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// 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,
          "tcpa": false,
          "carrier": "VERIZON WIRELESS",
          "rank": 1
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        }
      ]
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// 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": [],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Missing fields / name required for person lookup

{
  "first_name": [
    "first_name and last_name are required when find_owner is false."
  ]
}

402 β€” Insufficient credits

{
  "error": "Insufficient credits. Instant trace requires 5 credits per lookup. You have 0 credits."
}

503 β€” Skip trace service temporarily unavailable

{
  "error": "Skip trace service temporarily unavailable. Please try again."
}
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 + TCPA litigator 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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Column not found in your data

{
  "error": "Column \"parcel_id\" not found in data. Available: ['apn', 'county', 'state']"
}

400 β€” No usable parcel IDs

{
  "error": "No valid parcel IDs found after cleaning."
}

403 β€” Account suspended (unpaid invoices)

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

402 β€” Insufficient credits

{
  "error": "Insufficient credits. Parcel trace requires 5 credits per hit (worst case 2500 credits for 500 parcels). You have 0 credits."
}
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 + TCPA litigator flags and carrier, emails, plus property_owner, deceased, litigator, and age.

APN format: the # prefix is optional.

Rate limit: 500 requests per minute per user.

⚠️ Compliance: Phones returning litigator: true or dnc: true should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.

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,
          "tcpa": false,
          "carrier": "T-MOBILE USA INC.",
          "rank": 1
        },
        {
          "number": "5615550200",
          "type": "Landline",
          "dnc": true,
          "tcpa": false,
          "carrier": "BELLSOUTH TELECOMM INC",
          "rank": 2
        }
      ],
      "emails": [
        {
          "email": "[email protected]",
          "rank": 1
        },
        {
          "email": "[email protected]",
          "rank": 2
        }
      ]
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// Miss β€” 0 credits
{
  "parcel_id": "#00404033000001190",
  "county": "Palm Beach",
  "state": "FL",
  "hit": false,
  "persons_count": 0,
  "credits_deducted": 0,
  "persons": [],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Missing parcel_id / county / state

{
  "parcel_id": [
    "This field is required."
  ]
}

403 β€” Account suspended (unpaid invoices)

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

402 β€” Insufficient credits

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

503 β€” Skip trace service 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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Phone column not found in your CSV

{
  "error": "Column \"Phone\" not found in CSV"
}

400 β€” No usable phone numbers

{
  "error": "No valid phone numbers found"
}

403 β€” Account suspended (unpaid invoices)

{
  "error": "Account suspended due to unpaid invoices."
}

402 β€” Insufficient credits

{
  "error": "Insufficient credits. You need 150 credits for DNC scrubbing. You have 0."
}
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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

404 β€” Source trace queue not found

{
  "error": "No trace queue found with ID 37360"
}

400 β€” Source trace still processing

{
  "error": "This trace is still processing. Please wait until it completes."
}

400 β€” No phones in the selected columns

{
  "error": "No phone numbers found in this trace for the selected columns."
}

402 β€” Insufficient credits

{
  "error": "Insufficient credits. You need 23 credits for DNC scrubbing. You have 0."
}
GET

Fetch all DNC Queues

/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 including ones 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",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

404 β€” No DNC queue with that ID

{
  "error": "No DNC queue found with ID 5"
}

403 β€” DNC queue belongs to another account

{
  "error": "Permission denied"
}
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.

5 credits per lookup. Rate limited to 30 RPM per user.

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 β€” it self-paces and isn't subject to this 30 RPM limit.

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

⚠️ Compliance: Phones returning litigator: true or national_dnc: true should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.

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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// 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,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Missing or invalid phone

// No phone in body
{
  "error": "Missing 'phone' field."
}

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

402 β€” Insufficient credits

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

429 β€” Rate limit (30/min)

{
  "status": 429,
  "error": "DNC lookup limit exceeded. Max 30 lookups per 1 minute(s). For higher volume, use the batch endpoint /v1/api/dnc/scrub/ which respects upstream rate limits automatically.",
  "lookups_in_window": 30,
  "retry_after_seconds": 60
}

503 β€” DNC lookup not configured on this server

{
  "error": "DNC lookup service is not configured."
}

502 β€” Upstream temporarily unavailable

{
  "error": "DNC lookup service temporarily unavailable. Please try again."
}
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/property-search/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.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Example Request

curl 'https://tracerfy.com/v1/api/property-search/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": "zombie_property",
      "label": "Zombie Property",
      "description": "Vacant homes with an active pre-foreclosure filing β€” abandoned mid-foreclosure.",
      "default_filters": {
        "vacant": true,
        "pre_foreclosure": true
      }
    },
    {
      "key": "tax_delinquent",
      "label": "Tax Delinquent",
      "description": "Owners who fell behind on property taxes within the last 3 years.",
      "default_filters": {
        "tax_delinquent_year_min": 2023,
        "tax_delinquent_year_max": 2026
      }
    },
    {
      "key": "low_equity",
      "label": "Low Equity",
      "description": "Properties with roughly 30% equity or less β€” refi and short-sale outreach.",
      "default_filters": {
        "ltv_min": 70
      }
    },
    {
      "key": "vacant_land",
      "label": "Vacant Land",
      "description": "Undeveloped land parcels β€” land flipping and infill development.",
      "default_filters": {
        "property_type": "LAND"
      }
    },
    {
      "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": "failed_listing",
      "label": "Failed Listing",
      "description": "Listings that came off the market without selling β€” motivated re-list candidates.",
      "default_filters": {
        "mls_failed": 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": "2026-01-24",
        "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": {}
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}
POST

Preview Lead List

/v1/api/property-search/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.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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.
dedupe_from_history
body
boolean
No
When true, the response returns the post-dedupe count: properties this account has already received from past /execute/ calls with the same filter set are subtracted. The response gains three extra fields: dedupe_from_history (echoes the flag), excluded_from_history (how many propertyIds would be skipped), and available_after_dedupe (the new effective pool size). Defaults to false. Same-filter matching is hash-based and ignores click order of multi-strategy slugs and geography lists.

Example Request

curl -X POST 'https://tracerfy.com/v1/api/property-search/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,
    "dedupe_from_history": false
  }'

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"
  },
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

Preview with dedupe_from_history=true

{
  "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"
  },
  "dedupe_from_history": true,
  "excluded_from_history": 1200,
  "available_after_dedupe": 1140
}

400 β€” Unknown strategy

{
  "strategy": [
    "Unknown strategy 'not_a_real_strategy'. Valid options: call GET /v1/api/property-search/filters/"
  ]
}

400 β€” Disallowed filter key

{
  "filter_overrides": [
    "Disallowed filter keys: ['not_a_key']. See ALLOWED_FILTER_KEYS."
  ]
}

429 β€” Preview rate limit (500/hr)

{
  "status": 429,
  "error": "Lead Builder preview rate limit exceeded. Max 500 previews per hour.",
  "previews_in_window": 500
}

503 β€” Upstream temporarily unavailable

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

Execute Lead Build

/v1/api/property-search/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.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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.
dedupe_from_history
body
boolean
No
When true, the build excludes any propertyId your account has previously received from a past /execute/ call that used the same filter set (strategy + geography + filter_overrides). Useful for re-runs when you only want fresh leads. The match is hash-based β€” multi-strategy slug order and geography list order are normalized. To keep upstream cost bounded, the build fetches up to 5Γ— requested_count properties before truncating; if your filter pool is mostly exhausted, the final list may come in under your requested count (actual_count < requested_count) and you are only billed for delivered rows. Defaults to false (no exclusion).

Example Request

curl -X POST 'https://tracerfy.com/v1/api/property-search/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",
    "dedupe_from_history": false
  }'

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/",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Validation error

{
  "requested_count": [
    "Ensure this value is less than or equal to 25000."
  ]
}

400 β€” No matches (widen your filters)

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

402 β€” Insufficient credits

{
  "error": "Insufficient credits. This lead list requires up to 2500 credits (5 per row Γ— 500 rows). You have 100 credits.",
  "matches": 2340,
  "capped": 500
}

403 β€” Account suspended (unpaid invoices)

{
  "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/property-search/<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).

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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/property-search/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/",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// 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/",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

404 β€” Unknown or cross-account lead list ID

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

Lead List Rows (JSON)

/v1/api/property-search/<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 β€” all rows are reachable. The 500 is a page-size limit (most rows per response), not a cap on how many rows you can retrieve. per_page defaults to 100 (max 500); there's no upper bound on page β€” increment it to pull the whole list, and read total_rows / total_pages to know when you've reached the end. Returns 409 if the list is still processing.

Note: the seven property-signal columns added in v1.1 (foreclosure, tax_delinquent_year, tax_lien, quit_claim, mls_sold, mls_failed, area_median_income) are fully populated in the CSV download; this JSON endpoint currently returns them as empty strings for schema compatibility. foreclosure and auction statuses are verified against current filing records before delivery, so stale historical cases are not reported as active.

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.

⚠️ Compliance: Phones returning litigator: true or dnc: true should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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). No upper bound β€” page through every row.
per_page
query
integer
No
Rows per page (response size β€” not a cap on total rows). 1-500, default 100.

Example Request

curl 'https://tracerfy.com/v1/api/property-search/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",
      "latitude": 33.6359,
      "longitude": -112.0531,
      "apn": "123-45-6789",
      "subdivision": "Paradise Park",
      "property_type": "SFR",
      "property_use": "Single Family Residence",
      "land_use": "Residential",
      "year_built": 1985,
      "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,
      "roof_material": "Composition Shingle",
      "roof_construction": "Gable",
      "price_per_sqft": 227,
      "estimated_value": 485000,
      "estimated_equity": 298000,
      "equity_percent": 61.4,
      "assessed_value": 362000,
      "area_median_income": "",
      "last_sale_date": "2009-04-15",
      "last_sale_price": 187000,
      "years_owned": 16,
      "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,
      "document_type": "Warranty Deed",
      "quit_claim": "",
      "recording_date": "2009-04-17",
      "flood_zone": 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,
      "mobile_2": "",
      "mobile_2_dnc": false,
      "mobile_2_tcpa": false,
      "mobile_3": "",
      "mobile_3_dnc": false,
      "mobile_3_tcpa": false,
      "landline_1": "4805551234",
      "landline_1_dnc": false,
      "landline_1_tcpa": false,
      "landline_2": "",
      "landline_2_dnc": false,
      "landline_2_tcpa": false,
      "email_1": "[email protected]",
      "email_2": "",
      "email_3": "",
      "litigator": false,
      "has_contact": true,
      "contact_clean": true,
      "absentee_owner": false,
      "owner_occupied": true,
      "vacant": false,
      "free_clear": false,
      "high_equity": true,
      "pre_foreclosure": false,
      "foreclosure": "",
      "tax_delinquent": false,
      "tax_delinquent_year": "",
      "tax_lien": "",
      "inherited": false,
      "death": false,
      "judgment": false,
      "hoa": true,
      "category": "high_equity_refi_candidate",
      "mls_active": false,
      "mls_pending": false,
      "mls_cancelled": false,
      "mls_sold": "",
      "mls_failed": "",
      "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": 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",
      "latitude": 33.4892,
      "longitude": -111.9874,
      "apn": "987-65-4321",
      "subdivision": "Arcadia Heights",
      "property_type": "SFR",
      "property_use": "Single Family Residence",
      "land_use": "Residential",
      "year_built": 1972,
      "beds": 3,
      "baths": 2.0,
      "units_count": 1,
      "stories": 1,
      "building_size_sqft": 1680,
      "lot_size_sqft": 6200,
      "has_ac": true,
      "has_garage": true,
      "has_pool": true,
      "has_basement": false,
      "has_deck": false,
      "roof_material": "Tile/Clay",
      "roof_construction": "Hip",
      "price_per_sqft": 235,
      "estimated_value": 395000,
      "estimated_equity": 395000,
      "equity_percent": 100.0,
      "assessed_value": 288000,
      "area_median_income": "",
      "last_sale_date": "1998-11-03",
      "last_sale_price": 95000,
      "years_owned": 27,
      "prior_sale_date": null,
      "prior_sale_price": null,
      "open_mortgage_balance": 0,
      "lender_name": "",
      "estimated_mortgage_payment": 0,
      "total_properties_owned": 1,
      "total_portfolio_value": 395000,
      "cash_buyer": false,
      "corporate_owned": false,
      "document_type": "Warranty Deed",
      "quit_claim": "",
      "recording_date": "1998-11-05",
      "flood_zone": 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,
      "mobile_2": "",
      "mobile_2_dnc": false,
      "mobile_2_tcpa": false,
      "mobile_3": "",
      "mobile_3_dnc": false,
      "mobile_3_tcpa": false,
      "landline_1": "6025559900",
      "landline_1_dnc": false,
      "landline_1_tcpa": false,
      "landline_2": "",
      "landline_2_dnc": false,
      "landline_2_tcpa": false,
      "email_1": "[email protected]",
      "email_2": "",
      "email_3": "",
      "litigator": false,
      "has_contact": true,
      "contact_clean": true,
      "absentee_owner": true,
      "owner_occupied": false,
      "vacant": false,
      "free_clear": true,
      "high_equity": true,
      "pre_foreclosure": false,
      "foreclosure": "",
      "tax_delinquent": false,
      "tax_delinquent_year": "",
      "tax_lien": "",
      "inherited": false,
      "death": false,
      "judgment": false,
      "hoa": false,
      "category": "high_equity_absentee,free_and_clear",
      "mls_active": false,
      "mls_pending": false,
      "mls_cancelled": false,
      "mls_sold": "",
      "mls_failed": "",
      "mls_days_on_market": null,
      "mls_listing_price": null,
      "adjustable_rate": false,
      "investor_buyer": true,
      "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"
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

409 β€” Lead list still processing

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

404 β€” Unknown or cross-account lead list ID

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

Single-Address Lookup (Synchronous)

/v1/api/property-search/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.

Data quality: foreclosure and auction statuses are verified against current filing records, so stale historical cases are not reported as active.

Rate limit: 500 requests per minute.

⚠️ Compliance: Phones returning litigator: true or dnc: true should not be called for telemarketing or cold outreach without documented prior express written consent. TCPA violations can carry penalties. You are solely responsible for compliance with TCPA, FDCPA, and DNC regulations. These flags are informational, not legal advice.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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/property-search/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,
    "area_median_income": 82500,
    "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",
    "quit_claim": false,
    "recording_date": "2009-04-17",
    "price_per_sqft": 227,
    "absentee_owner": false,
    "owner_occupied": true,
    "vacant": false,
    "free_clear": false,
    "high_equity": true,
    "pre_foreclosure": false,
    "foreclosure": false,
    "tax_delinquent": false,
    "tax_delinquent_year": null,
    "tax_lien": false,
    "inherited": false,
    "death": false,
    "judgment": false,
    "hoa": true,
    "category": "high_equity_refi_candidate",
    "mls_active": false,
    "mls_pending": false,
    "mls_cancelled": false,
    "mls_sold": false,
    "mls_failed": 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
  },
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// Miss β€” address not found, 0 credits
{
  "hit": false,
  "credits_deducted": 0,
  "address": "999 Nowhere Blvd",
  "city": "Austin",
  "state": "TX",
  "zip_code": "78701",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

402 β€” Insufficient credits

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

403 β€” Account suspended (unpaid invoices)

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

503 β€” Upstream temporarily unavailable

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

429 β€” Rate limit (500/min)

{
  "status": 429,
  "error": "Rate limit exceeded. Max 500 lookups per minute.",
  "lookups_in_window": 500
}
POST

Address Autocomplete

/v1/api/property-search/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/property-search/lookup/ {
        "address":  match["street_address"],   # NOT match["address"]
        "city":     match["city"],
        "state":    match["state"],
        "zip_code": match["zip"],
    }


Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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/property-search/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)"
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Missing search field

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

429 β€” Autocomplete rate limit (30/min)

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

503 β€” 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/property-search/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.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

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/property-search/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,
  "meta": {
    "model": "traceai-1-20260321",
    "provider": "tracerfy",
    "prompt_version": "v1",
    "input_tokens": 0,
    "output_tokens": 0,
    "cost_usd": 0.02,
    "latency_ms": 842,
    "cached": false
  }
}

// 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
}

400 β€” Missing / too-long prompt or bad conversation_id

// Empty prompt
{
  "error": "Missing 'prompt' field."
}

// Over 2000 characters
{
  "error": "Prompt too long (max 2000 characters)."
}

// conversation_id is not a UUID
{
  "error": "Invalid conversation_id β€” must be a UUID."
}

402 β€” Insufficient credits

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

502 β€” AI provider error (not charged)

{
  "error": "AI assist failed: upstream model error"
}

503 β€” AI assist not configured on this server

{
  "error": "AI assist is not configured on this server.",
  "code": "ai_not_configured"
}

500 β€” Unexpected error

{
  "error": "AI assist hit an unexpected error. Please try again.",
  "code": "ai_unexpected"
}
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 (boolean β€” true when the owner's mailing address differs from the property), owner_occupied (boolean β€” opposite of absentee_owner; owner_occupied: true is translated to absentee_owner: false before the upstream query, and the preview response echoes it back as absentee_owner in filters_applied. Sending both keys in the same request is rejected with a 400), 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, foreclosure (boolean β€” active foreclosure, further along than pre_foreclosure), auction, reo, notice_type, tax_lien (boolean β€” a tax lien is recorded against the property), tax_delinquent_year_min, tax_delinquent_year_max (int, year β€” window in which the owner became tax delinquent), quit_claim (boolean β€” last transfer recorded via quitclaim deed), search_range β€” pair this with pre_foreclosure, auction, or reo to restrict results to filings within the last N months. Without it, those filters return every historical match. Accepted values: "1_MONTH", "3_MONTH", "6_MONTH".
MLSmls_active, mls_pending, mls_cancelled, mls_sold, mls_failed (boolean β€” listing came off the market without selling), 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
Area demographicsarea_median_income_min, area_median_income_max (number β€” median household income of the property's surrounding area). Accepted values: 1,000–99,999 β€” area income data ranges up to $99,999, so values outside that range are rejected with a 400. Use ONE bound per request β€” sending both in the same request is rejected with a 400.
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.
GET Β· POST

Saved Templates β€” List & Create

/v1/api/property-search/templates/
Description: A template is a saved, reusable lead-list configuration β€” a strategy, geography, and optional filter overrides you can re-run on demand or attach a Monitor to. Templates are free to create and store; you're only billed when you actually build a list from one via /execute/ (pass the template's id as template_id) or when a Monitor delivers.

GET returns your active templates. POST creates one. Templates are owner-scoped β€” you only ever see your own.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

Headers

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

Parameters

Name
In
Type
Required
Description
name
body
string
Yes
Label for the template (max 120 chars).
strategy
body
string
Yes
A preset key (or comma-separated keys) from GET /filters/, or 'custom'.
geography
body
object
Yes
Same shape as /execute/ β€” e.g. {"mode": "city", "cities": ["Phoenix"], "states": ["AZ"]}.
filter_overrides
body
object
No
Optional filters merged on top of the strategy. Validated against the same whitelist as /execute/.

Example Request

# Create a template
curl -X POST 'https://tracerfy.com/v1/api/property-search/templates/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Phoenix High-Equity Absentee",
    "strategy": "high_equity_absentee",
    "geography": {"mode": "city", "cities": ["Phoenix"], "states": ["AZ"]},
    "filter_overrides": {"year_built_max": 2015}
  }'

# List your templates
curl 'https://tracerfy.com/v1/api/property-search/templates/' \
  -H 'Authorization: Bearer '

Example Response 201

// POST β€” 201 Created
{
  "id": 7,
  "name": "Phoenix High-Equity Absentee",
  "strategy": "high_equity_absentee",
  "geography": {
    "mode": "city",
    "cities": [
      "Phoenix"
    ],
    "states": [
      "AZ"
    ]
  },
  "filter_overrides": {
    "year_built_max": 2015
  },
  "created_at": "2026-07-15T14:02:00Z",
  "updated_at": "2026-07-15T14:02:00Z",
  "last_run_at": null,
  "run_count": 0,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// GET β€” 200 (list)
{
  "templates": [
    {
      "id": 7,
      "name": "Phoenix High-Equity Absentee",
      "strategy": "high_equity_absentee",
      "geography": {
        "mode": "city",
        "cities": [
          "Phoenix"
        ],
        "states": [
          "AZ"
        ]
      },
      "filter_overrides": {
        "year_built_max": 2015
      },
      "created_at": "2026-07-15T14:02:00Z",
      "updated_at": "2026-07-15T14:02:00Z",
      "last_run_at": null,
      "run_count": 0
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

400 β€” Unknown strategy

{
  "strategy": [
    "Unknown strategy 'nope'. Valid options: call GET /v1/api/property-search/filters/"
  ]
}
GET Β· PATCH Β· DELETE

Template β€” Get, Update & Delete

/v1/api/property-search/templates/<id>/
Description: Read, rename/retune, or remove a single saved template.

GET returns the template. PATCH updates any of name, strategy, geography, or filter_overrides (partial β€” send only the fields you're changing). DELETE soft-deletes it (returns 204); it disappears from the list and future GETs return 404.

Editing or deleting a template does not affect any Monitor already created from it β€” Monitors snapshot their criteria at creation time. Cross-account IDs return 404.

Renamed from /v1/api/lead-builder/… β€” the previous path still works but is deprecated.

Headers

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

Parameters

Name
In
Type
Required
Description
id
path
integer
Yes
The template id.
name
body
string
No
(PATCH) New label.
strategy
body
string
No
(PATCH) New strategy key(s).
geography
body
object
No
(PATCH) New geography object.
filter_overrides
body
object
No
(PATCH) New overrides.

Example Request

# Rename
curl -X PATCH 'https://tracerfy.com/v1/api/property-search/templates/7/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Phoenix β€” Q3 Absentee"}'

# Delete (soft)
curl -X DELETE 'https://tracerfy.com/v1/api/property-search/templates/7/' \
  -H 'Authorization: Bearer '

Example Response 200

{
  "id": 7,
  "name": "Phoenix β€” Q3 Absentee",
  "strategy": "high_equity_absentee",
  "geography": {
    "mode": "city",
    "cities": [
      "Phoenix"
    ],
    "states": [
      "AZ"
    ]
  },
  "filter_overrides": {
    "year_built_max": 2015
  },
  "created_at": "2026-07-15T14:02:00Z",
  "updated_at": "2026-07-19T16:10:00Z",
  "last_run_at": null,
  "run_count": 0,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

204 β€” Deleted (no body)

404 β€” Unknown or cross-account template

{
  "error": "Template not found."
}
POST

Create a Monitor

/v1/api/property-monitors/
Description: A Monitor turns a lead-list configuration into a recurring, self-running subscription. On each scheduled run — daily or weekly, your choice — it computes the delta β€” matching properties in our property database that it hasn't delivered to you before β€” skip traces only those new ones, and delivers them as a CSV + webhook. If nothing new matched that run, nothing is delivered and nothing is charged.

Billing: 25 credits per new delivered lead β€” you only pay when new matching properties are found. A day with zero new matches costs zero.

Two ways to create (send exactly one form):
  • From a saved template: pass template_id. The template's strategy + geography + overrides are snapshotted onto the Monitor at creation, so later editing or deleting the template never changes what the Monitor delivers.
  • Inline: pass strategy + geography (+ optional filter_overrides), exactly like /execute/.
Sending both forms, or neither, returns 400. Up to 5 active monitors per account (higher limits for enterprise/reseller accounts on request).

Market size limit: a monitor can track up to 5,000 matching properties. If your strategy + geography matches more than that, creation returns 400 β€” narrow it (a tighter area, an equity band, a price range, or a property type).

First run: on creation we snapshot everything that already matches as your baseline β€” those existing properties are not delivered or charged. From then on you only receive properties that become new matches after you subscribed (a saved-search “new since” alert).

Headers

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

Parameters

Name
In
Type
Required
Description
template_id
body
integer
No
Clone criteria from one of your saved templates. Mutually exclusive with the inline fields below.
strategy
body
string
No
Inline form: preset key(s) from GET /filters/. Required when not using template_id.
geography
body
object
No
Inline form: same shape as /execute/. Required when not using template_id.
filter_overrides
body
object
No
Inline form: optional filters merged on top of the strategy.
name
body
string
No
Optional label. Defaults to the template's name when created from a template.
frequency
body
string
No
How often the monitor runs: daily or weekly. Defaults to daily.
max_rows_per_run
body
integer
No
Cap on new leads delivered per run. Default 500, max 25000.
monthly_spend_cap_credits
body
integer
No
Optional (nullable) ceiling on credits spent per calendar month. When reached, delivery pauses until the next month, then resumes automatically.
email_delivery
body
boolean
No
Email you each delivery's CSV. Defaults to true (independent of your account email preference).

Example Request

# Inline form
curl -X POST 'https://tracerfy.com/v1/api/property-monitors/' \
  -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},
    "name": "Phoenix High-Equity Absentee",
    "frequency": "weekly",
    "max_rows_per_run": 500,
    "monthly_spend_cap_credits": 5000,
    "email_delivery": true
  }'

# From a saved template (mutually exclusive with the inline fields)
curl -X POST 'https://tracerfy.com/v1/api/property-monitors/' \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"template_id": 7, "max_rows_per_run": 500}'

Example Response 201

{
  "id": 12,
  "name": "Phoenix High-Equity Absentee",
  "strategy": "high_equity_absentee",
  "strategy_label": "High Equity Absentee",
  "geography": {
    "mode": "city",
    "cities": [
      "Phoenix"
    ],
    "states": [
      "AZ"
    ]
  },
  "geography_label": "Phoenix, AZ",
  "frequency": "daily",
  "max_rows_per_run": 500,
  "monthly_spend_cap_credits": 5000,
  "email_delivery": true,
  "credits_per_row": 25,
  "baseline_count": 1284,
  "baseline_ready": true,
  "status": "active",
  "last_run_at": null,
  "next_run_at": "2026-07-20T11:30:00Z",
  "error_message": "",
  "consecutive_failures": 0,
  "created_at": "2026-07-19T16:00:00Z",
  "last_delivery_count": null,
  "source": "api",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

Webhook Delivery

When a Monitor delivers, Tracerfy POSTs to your account webhook_url with a lead_list payload carrying monitor_id / monitor_name β€” non-null only for monitor deliveries, so you can tell them apart from one-shot lists and route them. The payload hands you both URLs directly: download_url for the CSV, and rows_url to pull structured rows as JSON β€” no second call to figure out where to pull. Example payload:

{
  "id": 8123,
  "type": "lead_list",
  "name": "Monitor: Phoenix High-Equity Absentee β€” Jul 20, 2026",
  "strategy": "high_equity_absentee",
  "monitor_id": 12,
  "monitor_name": "Phoenix High-Equity Absentee",
  "created_at": "2026-07-20T11:31:02Z",
  "completed_at": "2026-07-20T11:34:18Z",
  "pending": false,
  "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/monitor_phoenix-high-equity-absentee_2026-07-20_a1b2c3d4.csv",
  "rows_url": "/v1/api/property-search/8123/rows/",
  "requested_count": 500,
  "actual_count": 37,
  "credits_deducted": 925
}

400 β€” Both forms supplied

{
  "non_field_errors": [
    "Provide EITHER template_id OR inline strategy+geography, not both."
  ]
}

400 β€” Neither form supplied

{
  "non_field_errors": [
    "Provide either template_id or inline strategy+geography."
  ]
}

400 β€” Active monitor cap reached

{
  "error": "You already have 5 active monitors (the maximum). Pause or delete one before creating another."
}

403 β€” Account suspended (unpaid invoices)

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

404 β€” template_id not found (or not yours)

{
  "error": "Template not found."
}
GET

List & Get Monitors

/v1/api/property-monitors/
Description: GET /monitors/ lists your monitors. GET /monitors/<id>/ returns a single monitor with its schedule (last_run_at, next_run_at), lifecycle status (active / paused / error), resolved credits_per_row, and last_delivery_count. Owner-scoped; unknown or cross-account IDs return 404.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
id
path
integer
No
Omit for the list; include for a single monitor.

Example Request

# List
curl 'https://tracerfy.com/v1/api/property-monitors/' \
  -H 'Authorization: Bearer '

# Detail
curl 'https://tracerfy.com/v1/api/property-monitors/12/' \
  -H 'Authorization: Bearer '

Example Response 200

// GET /monitors/ β€” 200 (list)
{
  "monitors": [
    {
      "id": 12,
      "name": "Phoenix High-Equity Absentee",
      "strategy": "high_equity_absentee",
      "strategy_label": "High Equity Absentee",
      "geography": {
        "mode": "city",
        "cities": [
          "Phoenix"
        ],
        "states": [
          "AZ"
        ]
      },
      "geography_label": "Phoenix, AZ",
      "frequency": "daily",
      "max_rows_per_run": 500,
      "monthly_spend_cap_credits": 5000,
      "email_delivery": true,
      "credits_per_row": 25,
      "baseline_count": 1284,
      "baseline_ready": true,
      "status": "active",
      "last_run_at": null,
      "next_run_at": "2026-07-20T11:30:00Z",
      "error_message": "",
      "consecutive_failures": 0,
      "created_at": "2026-07-19T16:00:00Z",
      "last_delivery_count": null,
      "source": "api"
    }
  ],
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

// GET /monitors/12/ β€” 200 (detail)
{
  "id": 12,
  "name": "Phoenix High-Equity Absentee",
  "strategy": "high_equity_absentee",
  "strategy_label": "High Equity Absentee",
  "geography": {
    "mode": "city",
    "cities": [
      "Phoenix"
    ],
    "states": [
      "AZ"
    ]
  },
  "geography_label": "Phoenix, AZ",
  "frequency": "daily",
  "max_rows_per_run": 500,
  "monthly_spend_cap_credits": 5000,
  "email_delivery": true,
  "credits_per_row": 25,
  "baseline_count": 1284,
  "baseline_ready": true,
  "status": "active",
  "last_run_at": null,
  "next_run_at": "2026-07-20T11:30:00Z",
  "error_message": "",
  "consecutive_failures": 0,
  "created_at": "2026-07-19T16:00:00Z",
  "last_delivery_count": null,
  "source": "api",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

404 β€” Unknown or cross-account monitor

{
  "error": "Monitor not found."
}
POST Β· DELETE

Pause, Resume & Delete

/v1/api/property-monitors/<id>/…
Description: Control a monitor's lifecycle:
  • POST /monitors/<id>/pause/ β€” pause the monitor. It stops running until you resume it, and keeps its history.
  • POST /monitors/<id>/resume/ β€” resume a paused monitor. It starts running again on its schedule.
  • DELETE /monitors/<id>/ β€” delete the monitor. It stops running and is removed from your account; the lead lists and CSVs it already delivered stay available. Returns 204.
All three are owner-scoped; unknown or cross-account IDs return 404.

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
id
path
integer
Yes
The monitor id.

Example Request

# Pause
curl -X POST 'https://tracerfy.com/v1/api/property-monitors/12/pause/' \
  -H 'Authorization: Bearer '

# Resume
curl -X POST 'https://tracerfy.com/v1/api/property-monitors/12/resume/' \
  -H 'Authorization: Bearer '

# Delete
curl -X DELETE 'https://tracerfy.com/v1/api/property-monitors/12/' \
  -H 'Authorization: Bearer '

Example Response 200

{
  "id": 12,
  "name": "Phoenix High-Equity Absentee",
  "strategy": "high_equity_absentee",
  "strategy_label": "High Equity Absentee",
  "geography": {
    "mode": "city",
    "cities": [
      "Phoenix"
    ],
    "states": [
      "AZ"
    ]
  },
  "geography_label": "Phoenix, AZ",
  "frequency": "daily",
  "max_rows_per_run": 500,
  "monthly_spend_cap_credits": 5000,
  "email_delivery": true,
  "credits_per_row": 25,
  "baseline_count": 1284,
  "baseline_ready": true,
  "status": "paused",
  "last_run_at": null,
  "next_run_at": "2026-07-20T11:30:00Z",
  "error_message": "",
  "consecutive_failures": 0,
  "created_at": "2026-07-19T16:00:00Z",
  "last_delivery_count": null,
  "source": "api",
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

204 β€” Deleted (no body)

404 β€” Unknown or cross-account monitor

{
  "error": "Monitor not found."
}
GET

Monitor Delivery History (Runs)

/v1/api/property-monitors/<id>/runs/
Description: Returns the lead lists a monitor has delivered, newest first. Each run is a normal Lead Builder list β€” poll or download it exactly like an /execute/ result. Every run carries a rows_url (pull structured rows as JSON) and a download_url (CSV) directly β€” you never have to build those URLs yourself.

Paginated β€” full history is always reachable. The 500 is a page-size limit (the most runs a single response returns) β€” not a cap on how much history you can retrieve. There's no upper bound on page: every delivery a monitor has ever made stays retrievable. per_page defaults to 100 (max 500); increment page to walk older runs, and read total_runs / total_pages to know when you've reached the end. Newest first. Runs in progress show status: "pending" with an empty download_url (their rows_url returns 409 until the run finishes).

Headers

  • Authorization = Bearer <YOUR_TOKEN>

Parameters

Name
In
Type
Required
Description
id
path
integer
Yes
The monitor id.
page
query
integer
No
1-based page number (newest first). Defaults to 1.
per_page
query
integer
No
Runs per page (response size β€” not a cap on total history). Defaults to 100, max 500.

Example Request

curl 'https://tracerfy.com/v1/api/property-monitors/12/runs/' \
  -H 'Authorization: Bearer '

Example Response 200

{
  "runs": [
    {
      "id": 8123,
      "name": "Monitor: Phoenix High-Equity Absentee β€” Jul 20, 2026",
      "strategy": "high_equity_absentee",
      "strategy_label": "High Equity Absentee",
      "status": "complete",
      "created_at": "2026-07-20T11:31:02Z",
      "completed_at": "2026-07-20T11:34:18Z",
      "requested_count": 500,
      "actual_count": 37,
      "credits_deducted": 925,
      "monitor_id": 12,
      "monitor_name": "Phoenix High-Equity Absentee",
      "download_url": "https://tracerfy.nyc3.cdn.digitaloceanspaces.com/tracerfy/monitor_phoenix-high-equity-absentee_2026-07-20_a1b2c3d4.csv",
      "rows_url": "/v1/api/property-search/8123/rows/"
    }
  ],
  "total_runs": 128,
  "page": 1,
  "per_page": 100,
  "total_pages": 2,
  "meta": {
    "request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "timestamp": "2026-07-16T18:22:05Z",
    "api_version": "2026-03-21"
  }
}

404 β€” Unknown or cross-account monitor

{
  "error": "Monitor not found."
}
REF

Connect via AI Assistants (MCP)

Model Context Protocol connector
Description: Connect Tracerfy to your AI assistant (e.g. Claude) via the Model Context Protocol (MCP) and run skip traces, DNC checks, and lead lists in plain English. Same billing as the API: pay per hit; misses cost nothing.

Generate a personal connector link in your profile under Connect via MCP (https://mcp.tracerfy.com/u/<token>/mcp) β€” the token in the URL authenticates as you, so keep it private. Connect it one of these ways:
  • Custom connector: in your AI assistant's connector settings, add a custom connector and paste the link as the server URL β€” most MCP-capable assistants support this.
  • MCP config file (MCP-compatible apps & IDEs): use the JSON below.
  • Programmatic API: pass the connector in your request's mcp_servers β€” full example below (shown for the Claude API).
Example prompts:
  • "Skip trace 123 Main St, Phoenix AZ and check the number against Do-Not-Call."
  • "How many vacant, high-equity homes are in Dallas?"
  • "Build me a list of 500 absentee owners in Miami-Dade."
  • "What's my Tracerfy credit balance?"
Available tools:
  • trace_lookup / parcel_lookup β€” owner phones & emails by address or parcel (APN)
  • dnc_check β€” Do-Not-Call / TCPA compliance for a phone
  • lead_lookup β€” full property + owner dossier for an address
  • preview_lead_list (free) & execute_lead_list β€” size and build lead lists
  • get_lead_list_status / get_lead_list_rows β€” track and fetch results
  • list_strategies, check_balance β€” presets/filters and your credits (free)

Example Request

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: mcp-client-2025-11-20" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Skip trace 123 Main St, Phoenix AZ and check the phone against Do-Not-Call."}
    ],
    "mcp_servers": [
      {
        "type": "url",
        "url": "https://mcp.tracerfy.com/u/<token>/mcp",
        "name": "tracerfy"
      }
    ],
    "tools": [
      {
        "type": "mcp_toolset",
        "mcp_server_name": "tracerfy"
      }
    ]
  }'

TypeScript (Anthropic SDK)

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic(); // reads ANTHROPIC_API_KEY

const message = await client.beta.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [
    { role: "user", content: "Skip trace 123 Main St, Phoenix AZ and check the phone against Do-Not-Call." },
  ],
  mcp_servers: [
    { type: "url", url: "https://mcp.tracerfy.com/u/<token>/mcp", name: "tracerfy" },
  ],
  tools: [
    { type: "mcp_toolset", mcp_server_name: "tracerfy" },
  ],
  betas: ["mcp-client-2025-11-20"],
});

console.log(message.content);

MCP config file (Claude Desktop & MCP-compatible clients)

{
  "mcpServers": {
    "tracerfy": {
      "url": "https://mcp.tracerfy.com/u/<token>/mcp"
    }
  }
}